【狀壓 dp】A003_LC_最小的必要團隊(Map)

一、Problem

作爲項目經理,你規劃了一份需求的技能清單 req_skills,並打算從備選人員名單 people 中選出些人組成一個「必要團隊」( 編號爲 i 的備選人員 people[i] 含有一份該備選人員掌握的技能列表)。

所謂「必要團隊」,就是在這個團隊中,對於所需求的技能列表 req_skills 中列出的每項技能,團隊中至少有一名成員已經掌握。

我們可以用每個人的編號來表示團隊中的成員:例如,團隊 team = [0, 1, 3] 表示掌握技能分別爲 people[0],people[1],和 people[3] 的備選人員。

請你返回 任一 規模最小的必要團隊,團隊成員用人員編號表示。你可以按任意順序返回答案,本題保證答案存在。

輸入:req_skills = ["java","nodejs","reactjs"], people = [["java"],["nodejs"],["nodejs","reactjs"]]
輸出:[0,2]

提示:

1 <= req_skills.length <= 16
1 <= people.length <= 60
1 <= people[i].length, req_skills[i].length, people[i][j].length <= 16
req_skills 和 people[i] 中的元素分別各不相同
req_skills[i][j], people[i][j][k] 都由小寫英文字母組成
本題保證「必要團隊」一定存在

二、Solution

方法一:dp

思路

需滿足的技能數量很小,暗示我們可以將團隊的技能狀態用一個整形變量來記錄;首先在狀態轉移之前,我們肯定需要得到某一個人的掌握的技能,然後將該人的技能狀態跟已經存在的團隊的技能狀態 j 相融合,設融合後的狀態爲 y:

  • 如果狀態 y 之前不存在,那麼團隊技能狀態 y 所需的人數直接加上該人
  • 如果狀態 y 之前存在過,那麼團隊技能狀態 y 所需的人數應該與狀態爲 jj 時加上 1 人對比,看誰所需人數少

算法

  • 定義狀態
    • f[i]f[i] 表示團隊中技能滿足狀態爲 ii 時,所需要的最少人數
  • 思考初始化:
    • f[0]=0f[0] = 0 表示沒有任何一項技能滿足時的團隊需要 0 個人
    • f[1...tot]=1f[1...tot] = -1
  • 思考狀態轉移方程
    • 如果 f[y]=1f[y] = -1 或者 f[y]>f[j]+1f[y] > f[j] + 1,則 f[y]=f[j]+1f[y] = f[j] + 1
  • 思考輸出:輸出滿足所有能後的最少人數團隊成員編號。

由於字符串難以做成位操作,所以要將字符串和技能編號映射起來。

class Solution {
    public int[] smallestSufficientTeam(String[] rss, List<List<String>> ps) {
    	int n = rss.length, m = ps.size(), tot = (1 << n) - 1, f[] = new int[tot+1];
    	Arrays.fill(f, -1);
    	f[0] = 0;
    	Map<String, Integer> mp = new HashMap<>();
    	Map<Integer, List<Integer>> team = new HashMap<>();
    	for (int i = 0; i < n; i++)     mp.put(rss[i], i);
        for (int i = 0; i <= tot; i++)  team.put(i, new LinkedList<>());

    	for (int i = 0; i < m; i++) {
    		int x = 0;
    		for (String s : ps.get(i))
    			x |= 1 << mp.get(s);
    		for (int j = 0; j <= tot; j++) if (f[j] != -1) {
    			int y = j | x;
    			if (f[y] == -1 || f[y] > f[j] + 1) {
    				f[y] = f[j] + 1;
    				team.get(y).clear();
                    team.get(y).addAll(team.get(j));
    				team.get(y).add(i);
    			}
    		}
    	}
    	int sz = team.get(tot).size(), i = 0, ans[] = new int[sz];
    	for (int pID : team.get(tot)) 
    		ans[i++] = pID;
    	return ans;
    }
}

複雜度分析

  • 時間複雜度:O(m×(1<<n))O(m × (1 << n))
  • 空間複雜度:O(1<<n)O(1<<n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章