Given a set of candidate numbers (C) (without duplicates) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
例如: [2, 3, 6, 7] and target 7面試
[ [7], [2, 2, 3] ]
給定一個數組(元素無重複),和一個目標值,找到全部組合,加起來等於目標值。數組中的元素能夠重複使用.
解法:數組
public class CombinationSum { public static List<List<Integer>> combinationSum(int[] candidates, int target){ Arrays.sort(candidates); List<List<Integer>> result = new ArrayList<>(); getResult(result, new ArrayList<Integer>(), candidates, target, 0); return result; } private static void getResult(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) { if(target<0) return; if(target==0){ result.add(new ArrayList<>(current)); return; } for(int i = start; i<candidates.length && target >= candidates[i]; i++){ current.add(candidates[i]); getResult(result, current, candidates, target-candidates[i], i); current.remove(current.size() - 1); } } public static void main(String[] args) { int[] nums = {2,3,6,7}; System.out.println(combinationSum(nums, 7)); } }
給定一個數組(元素能夠有重複),和一個目標值,找到全部組合,加起來等於目標值。數組中的元素不能重複使用。
例子: [10, 1, 2, 7, 6, 1, 5] and target 8code
[ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]
解法:遞歸
/** * 要去重,注意邊界,遞歸時候要加一 */ public class CombinationSum2 { public List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> result = new ArrayList<>(); Arrays.sort(candidates); dfs(result, new ArrayList<Integer>(), candidates, target, 0); return result; } private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) { if(target < 0) return; if(target == 0){ result.add(new ArrayList<Integer>(current)); return; } for(int i = start; i<candidates.length && target >= candidates[i]; i++){ current.add(candidates[i]); dfs(result, current, candidates, target - candidates[i], i+1); // 此處注意i+1,每一個元素只能用一次,加一後在向下遞歸 current.remove(current.size()-1); while(i < candidates.length - 1 && candidates[i] == candidates[i+1]) i++; // 去重複(注意上面有i+1,這裏要length-1,邊界問題) } } public static void main(String[] args) { int[] array = {10, 1, 2, 7, 6, 1, 5}; int target = 8; System.out.println(new CombinationSum2().combinationSum2(array, target)); } }
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.rem
Example 1: Input: k = 3, n = 7get
Output: [[1,2,4]]
Example 2: Input: k = 3, n = 9it
Output: [[1,2,6], [1,3,5], [2,3,4]]
給定K和N,從1--9中這幾個9個數字組合出來K個數,其和爲N。1-9不能重複使用.io
/** * 注意結束條件:size達到k值 而且 剩餘值爲0 */ public class CombinationSum3 { public List<List<Integer>> combinationSum3(int k, int n) { List<List<Integer>> result = new ArrayList<>(); dfs(result, new ArrayList<Integer>(), k, n, 1); return result; } private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int k, int remainder, int start){ if(current.size() == k && remainder == 0){ //size達到k值 而且 剩餘值爲0 result.add(new ArrayList<>(current)); return ; } for(int i = start; i<=9 && remainder >= i; i++){ current.add(i); dfs(result, current, k, remainder - i, i+1); // 不重複,i+1 current.remove(current.size() - 1); } } public static void main(String[] args) { System.out.println(new CombinationSum3().combinationSum3(3, 15)); } }
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.class
Example: nums = [1, 2, 3], target = 4
The possible combination ways are:基礎
(1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)
Note that different sequences are counted as different combinations.
Therefore the output is 7.
Follow up: What if negative numbers are allowed in the given array?
How does it change the problem? What limitation we need to add to the
question to allow negative numbers?若是有負數,就不能讓數組中的元素重複使用。
給定一個正整數數組(元素無重複),給定目標target,找出組合的個數,使得組合中元素的和等於target。數組元素能夠重複使用.
public class CombinationSum4 { public int combinationSum4(int[] candidates, int target){ List<List<Integer>> result = new ArrayList<>(); dfs(result, new ArrayList<Integer>(), candidates, target, 0); return result.size(); } private void dfs(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) { if(target < 0) return; if(target == 0){ result.add(new ArrayList<>(current)); return; } for(int i = 0; i<candidates.length && target >= candidates[i]; i++){ current.add(candidates[i]); dfs(result, current, candidates, target-candidates[i], i); current.remove(current.size() - 1); } } public static void main(String[] args) { int[] arr = {1,2,3}; System.out.println(new CombinationSum4().combinationSum4(arr, 4)); } }
遞歸調用循環中,對於第一題修改i的起始位置便可:i = 0
可是TLE。遞歸深度太深。
因此這個方法是不行的。
須要使用DP。
public int combinationSum4(int[] candidates, int target){ Arrays.sort(candidates); int[] dp = new int[target + 1]; dp[0] = 1; for(int i = 1; i<dp.length; i++){ for(int curr: candidates){ if(curr > i) break; dp[i] += dp[i - curr]; } } return dp[target]; }
有道面經題目是一個修改版,也是返回組合個數便可,可是加了條件:去掉重複。
上面的例子:nums = [1, 2, 3] target = 4 ,返回 7.
The possible combination ways are: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)
這個題目要返回的是4,全部的組合是:(1, 1, 1, 1) (1, 1, 2) (1, 3) (2, 2) (3, 1)
變成第一題了:須要改變返回值,返回大小便可。
看一下這幾個的區別,輕微的改動,產生的不一樣結果:
以第一題Combination Sum I爲基礎:
public class CombinationSum { public static List<List<Integer>> combinationSum(int[] candidates, int target){ Arrays.sort(candidates); List<List<Integer>> result = new ArrayList<>(); getResult(result, new ArrayList<Integer>(), candidates, target, 0); return result; } private static void getResult(List<List<Integer>> result, ArrayList<Integer> current, int[] candidates, int target, int start) { if(target < 0) return; // 是有可能小於0的 if(target == 0){ result.add(new ArrayList<>(current)); // 此處注意 return; } // 注意點1 for(int i = start; i<candidates.length && target >= candidates[i]; i++){ current.add(candidates[i]); getResult(result, current, candidates, target-candidates[i], i); // 注意點2 current.remove(current.size() - 1); } } public static void main(String[] args) { int[] nums = {1,2,3}; System.out.println(combinationSum(nums, 4)); } }
在上面的兩個注意點上:
第一題:數組(元素無重複),數組中的元素能夠重複使用。結果
[[1, 1, 1, 1], [1, 1, 2], [1, 3], [2, 2]]
若是第一處修改爲 i = 0 結果變爲:
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1]]
若是第一處修改成 i = start 以及 第二處修改成 i+1 結果變爲:
[[1, 3]]