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]]