給定候選數組 candidates(可含重複)與目標 target,找出所有不重複組合,使和為 target。每個數字在每個組合中最多用一次。輸出組合內非遞減,解集無重複。
數組排序後,相同數字相鄰。回溯時,同一層級若已用過某數值,直接跳過後續相同值,避免生成重複組合。
for (int i = start; i < n; i++) {
if (i > start && candidates[i] == candidates[i-1]) continue; // 關鍵去重
// ...
}
class Solution {
public:
vector> combinationSum2(vector& candidates, int target) {
sort(candidates.begin(), candidates.end());
vector> res;
vector path;
dfs(candidates, target, 0, path, res);
return res;
}
private:
void dfs(const vector& c, int target, int start,
vector& path, vector>& res) {
if (target == 0) { res.push_back(path); return; }
for (int i = start; i < (int)c.size(); i++) {
if (i > start && c[i] == c[i-1]) continue; // 同層去重
if (c[i] > target) break; // 剪枝:有序數組後續更大
path.push_back(c[i]);
dfs(c, target - c[i], i + 1, path, res); // i+1:每個數只用一次
path.pop_back();
}
}
};
| 特性 | Combination Sum I (39) | Combination Sum II (40) |
|---|---|---|
| 候選數重複 | 無 | 可重複 |
| 每個數使用次數 | 無限 | 最多一次 |
| 去重策略 | 無需 | 同層 i > start && c[i]==c[i-1] |
| 遞歸下一起點 | i (可復用) | i+1 (不可復用) |
輸入:candidates = [10,1,2,7,6,1,5], target = 8
排序後:[1,1,2,5,6,7,10]
輸出:
[1, 1, 6] [1, 2, 5] [1, 7] [2, 6]
Combination Sum II 的靈魂在於「排序 + 同層去重 + 目標值剪枝」三板斧。掌握此模板,Subsets II、Permutations II 等所有「含重複元素的組合/排列/子集」問題皆可類推。面試手寫時,i > start 條件務必寫對——這是去重的核心守門員。