題目描述(題目難度,中等)
給定一個數組 candidates
和一個目標數 target
,找出 candidates
中所有可以使數字和爲 target
的組合。
candidates
中的每個數字在每個組合中只能使用一次。
說明:
- 所有數字(包括目標數)都是正整數。
- 解集不能包含重複的組合。
示例 1:
輸入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集爲:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
輸入: candidates = [2,5,2,1,2], target = 5,
所求解集爲:
[
[1,2,2],
[5]
]
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/combination-sum-ii
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
題目求解
使用遞歸求解,遞歸的過程其實就是一個選數的過程,只要遞歸過程中,所選數的和不超過目標數 target,就把所選的數保存到臨時列表中。一旦所選數的和等於 target,就將臨時列表加入結果集。
參考代碼如下:
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(candidates); // 去重的第一步
comSum(candidates, target, result, new ArrayList<>(), 0);
return result;
}
void comSum(int[] can, int tar, List<List<Integer>> res, List<Integer> canRes, int low){
if(tar == 0){
res.add(new ArrayList<>(canRes));
return;
}
for(int i = low; i < can.length; ++i){
if(i > low && can[i-1] == can[i]) continue; // 去重的第二步
if(can[i] <= tar){
canRes.add(can[i]);
comSum(can, tar-can[i], res, canRes, i+1);
canRes.remove(canRes.size()-1);
}else return;
}
}
}
遞歸函數最後一個參數表示的是選數的起始位置,i 表示當前所選數的位置,那麼遞歸時最後一個實參置爲 i+1,表示下次會在當前所選數的後面開始選數,這樣就能滿足題目“每個數字在每個組合中只能使用一次”的要求。
但由於 candidates 數組中本身會有重複數字出現,所以單純按 和等於 target 的條件去選,會有重複的組合出現。爲了在遞歸時就去掉重複組合,就需要將 candidates 數組排序,把相同的數聚在一起(其實只要能把相同的數聚在一起,不排序也可以),然後增加判斷條件 i > low && can[i-1] == can[i]
,就可以將重複組合過濾掉,這個條件一定要細心體會,leetcode 之前的題目三數之和的解法二中也使用了同樣的方法去重。