LeetCode筆記——40組合總和Ⅱ
題目:給定一個數組 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] ]
思路一:
搜尋新組合時從下一個元素開始;去重時通過HashSet取出重複。在這段程式碼中定義了類變數,使得整個類中都可以使用
class Solution { int n; //類變數 int nums[]; List<List<Integer>>result;
//遞迴查詢的方法,返回結果result public List<List<Integer>> find(List<Integer>values,int index,int reserve){ if(reserve==0){ //遞迴結束的標誌,找到了一組組合 ArrayList<Integer>item=new ArrayList<Integer>(); item.addAll(values); result.add(item); //新增到最終的結果中 } for(int i=index;i<=n;i++) //遞迴尋找組合 { if(nums[i-1]<
return newList; } }
思路 二
本題與39題相比主要有兩點不同。第一是本題中存在重複節點;第二是每個節點只能使用一次,類似於圖中的沒有自環出現。對於第二個問題來說,每次搜尋新路徑的時候從它的下一個節點開始就可以解決;對於去重問題,以下程式碼採用的是先對陣列進行排序,將所有相同權值的節點都放在一起,這樣可以方便跳過這些節點。
參考網上大神的程式碼:
class Solution { public List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> res = new ArrayList<>(); if (candidates == null || candidates.length == 0 || target < 0) return res; List<Integer> list = new ArrayList<>(); Arrays.sort(candidates); //排序,使得尋找相同出權值的節點變得容易 get(candidates, target, 0, list, res); return res; } private void get(int[] candidates, int target, int i, List<Integer> list, List<List<Integer>> res) { if (i > candidates.length || target < 0) return; //因為沒有自環,所以每次都是從下一個節點開始搜尋,要新增一個條件判斷節點仍在圖中 if (target == 0) { //滿足條件,新增至結果集 res.add(new ArrayList<>(list)); return; } for (int p = i; p < candidates.length; p++) { list.add(candidates[p]); //新增節點到路徑 get(candidates, target - candidates[p], p+1, list, res); //因為沒有自環,所以每次搜尋更新路徑權值後的下一個節點 list.remove(list.size()-1); //回溯,將當前節點從路徑中剔除 while (p < candidates.length - 1 && candidates[p] == candidates[p+1]) p++; //因為存在重複節點,所以已經被剔除的節點不能再被放回到路徑中 } } }
執行最快的程式碼:
具體的執行情況弄不懂。。。。。是怎麼進行去重的。。。。
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> ans = new LinkedList<>();
Arrays.sort(candidates);
backTrack(candidates, target, 0, ans, new LinkedList<Integer>(), false);
return ans;
}
public void backTrack(int[] candidates, int target, int index, List<List<Integer>> ans, List<Integer> tmp, boolean used) {
if(target == 0) {
ans.add(new ArrayList(tmp));
} else if(target > 0 && index < candidates.length) {
int item = candidates[index];
if(item <= target) {
backTrack(candidates, target, index + 1, ans, tmp, false);
// 去重
if(!(!used && index > 0 && candidates[index] == candidates[index - 1])) {
tmp.add(item);
backTrack(candidates, target - item, index + 1, ans, tmp, true);
tmp.remove(tmp.size() - 1);
}
}
}
}
}