Combination Sum I
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));
}
}
LC40. Combination Sum II
给定一个数组(元素可以有重复),和一个目标值,找到所有组合,加起来等于目标值。数组中的元素不能重复使用。
例子: [10, 1, 2, 7, 6, 1, 5] and target 8
[
[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));
}
}
LC216. Combination Sum III
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.
Example 1: Input: k = 3, n = 7
Output: [[1,2,4]]
Example 2: Input: k = 3, n = 9
Output: [[1,2,6], [1,3,5], [2,3,4]]
给定K和N,从1--9中这几个9个数字组合出来K个数,其和为N。1-9不能重复使用.
/**
* 注意结束条件: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));
}
}
LC 377. Combination Sum IV
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.
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]]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。