題目連接: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 }
剪枝,先排序,而後在遞歸的時候,一旦總和<=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 }
另外一個方法剪枝,不用等到總和<=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 }