39.Combination Sum

題目連接:https://leetcode.com/problems/combination-sum/description/數組

題目大意:給出一串數字(沒有重複數字)和一個數字,找出全部組合數的和與這個數字相等的組合數,其中組合數的每個數字能夠重複選,例子以下:ide

法一:利用78題的法一,只是這裏對target有所限制,還要注意能夠重複取數字。代碼以下(耗時23ms):spa

 1     public List<List<Integer>> combinationSum(int[] candidates, int target) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         dfs(res, tmp, candidates, target, 0);
 5         return res;
 6     }
 7     public static void dfs(List<List<Integer>> res, List<Integer> tmp, int[] candidates, int target, int start) {
 8         if(target == 0) {//遞歸結束條件
 9             res.add(new ArrayList<Integer>(tmp));
10             return;
11         }
12         else if(target > 0){//這裏必定要判斷target>0,由於若是不判斷就會致使target<0時還在往下遞歸
13             for(int i = start; i < candidates.length; i++) {
14                 tmp.add(candidates[i]);
15                 dfs(res, tmp, candidates, target - candidates[i], i);//這裏不是i+1而是i,由於能夠重複選
16                 tmp.remove(tmp.size() - 1);
17             }
18         }
19     }
View Code

剪枝,先排序,而後在遞歸的時候,一旦總和<=0則跳出後面的循環。代碼以下(耗時18ms):code

 1     public List<List<Integer>> combinationSum(int[] candidates, int target) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         Arrays.sort(candidates);//先進行排序
 5         dfs(res, tmp, candidates, target, 0);
 6         return res;
 7     }
 8     public static boolean dfs(List<List<Integer>> res, List<Integer> tmp, int[] candidates, int target, int start) {
 9         if(target < 0) {
10             return false;
11         }
12         if(target == 0) {//遞歸結束條件
13             res.add(new ArrayList<Integer>(tmp));
14             return false;
15         }
16         else {//這裏必定要判斷target>0,由於若是不判斷就會致使target<0時還在往下遞歸
17             for(int i = start; i < candidates.length; i++) {
18                 tmp.add(candidates[i]);
19                 boolean flag = dfs(res, tmp, candidates, target - candidates[i], i);//這裏不是i+1而是i,由於能夠重複選
20                 tmp.remove(tmp.size() - 1);
21                 //剪枝,由於數組是排好序的,因此一旦總和<=0,那麼其後的數字必定會致使當前結果<0,因此能夠直接今後跳事後面的循環
22                 if(flag == false) {
23                     break;
24                 }
25             }
26         }
27         return true;
28     }
View Code

 另外一個方法剪枝,不用等到總和<=0才剪枝,而是在dfs以前就判斷是否能選該數,不然就跳出循環。代碼以下(耗時15ms):blog

 1     public List<List<Integer>> combinationSum(int[] candidates, int target) {
 2         List<List<Integer>> res = new ArrayList<List<Integer>>();
 3         List<Integer> tmp = new ArrayList<Integer>();
 4         Arrays.sort(candidates);
 5         dfs(res, tmp, candidates, target, 0);
 6         return res;
 7     }
 8     public static void dfs(List<List<Integer>> res, List<Integer> tmp, int[] candidates, int target, int start) {
 9         if(target == 0) {//遞歸結束條件
10             res.add(new ArrayList<Integer>(tmp));
11             return;
12         }
13         else if(target > 0){//這裏必定要判斷target>0,由於若是不判斷就會致使target<0時還在往下遞歸
14             for(int i = start; i < candidates.length; i++) {
15                 //快速剪枝
16                 if(target < candidates[i]) {
17                     break;
18                 }
19                 tmp.add(candidates[i]);
20                 dfs(res, tmp, candidates, target - candidates[i], i);//這裏不是i+1而是i,由於能夠重複選
21                 tmp.remove(tmp.size() - 1);
22             }
23         }
24     }
View Code
相關文章
相關標籤/搜索