您的位置:首页 > 编程语言 > Java开发

Leetcode: Combination Sum

2017-07-30 22:24 357 查看
已知数组C和目标值T,要求在C中找出所有独特的组合使其和为T,C中所有的数和T都为正整数

39. Combination Sum

Note:

1. C中无重复

2. 同一个数在组合中可以出现任意次

比如C=[2, 3, 6, 7] ,T=7, 解为

[
[7],
[2, 2, 3]
]


解法

简单回溯

public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
findCombination(result, new ArrayList<Integer>(), candidates,  target, 0);
return result;
}

public void findCombination(List<List<Integer>> result, List<Integer> combinations, int[] candidates, int remain, int start){
if(remain < 0) return;
if (remain == 0){
result.add(new ArrayList<Integer>(combinations));
}
//每递归一层for循环确定一个位置的数,如第k层for循环就确定第k个数
for(int i = start; i < candidates.length; i++) {
combinations.add(candidates[i]);
findCombination(result, combinations, candidates, remain - candidates[i], i);//start置为i表明允许多次使用同一个数
combinations.remove(combinations.size()-1);
}
}
}


简单回溯 + 排序优化

public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
//排序优化
Arrays.sort(candidates);
findCombination(result, new ArrayList<Integer>(), candidates,  target, 0);
return result;
}

public void findCombination(List<List<Integer>> result, List<Integer> combinations, int[] candidates, int remain, int start){
if(remain < 0) return;
if (remain == 0){
result.add(new ArrayList<Integer>(combinations));
}
//每递归一层for循环确定一个位置的数,如第k层for循环就确定第k个数
for(int i = start; i < candidates.length && candidates[i] <= remain; i++) { //当c[i]大于remain,则i以及i以后的都不会符合
combinations.add(candidates[i]);
findCombination(result, combinations, candidates, remain - candidates[i], i);
combinations.remove(combinations.size()-1);
}
}
}


40. Combination Sum II

Note:

1. C中可能有重复值

2. C中的每一个数在组合中只能出现一次

如C = [10, 1, 2, 7, 6, 1, 5], T = 8, 解为

[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]


解法

利用排序去重

public class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(candidates);//先排序以便去重
findCombination(result, new ArrayList<Integer>(), candidates,  target, 0);
return result;
}

public void findCombination(List<List<Integer>> result, List<Integer> combinations, int[] candidates, int remain, int start){
if(remain < 0) return;
if (remain == 0){
result.add(new ArrayList<Integer>(combinations));
}
//每层for循环确定一个位置的数,如第k层确定第k个数
for(int i = start; i < candidates.length && candidates[i] <= remain; i++) {
//保证当前位置不会重复使用相等的数,如1,1,2,5,6,7,10,位置0只可能使用第一个1,位置1只可能使用第二个1
if(i > start && candidates[i] == candidates[i-1]) continue;
combinations.add(candidates[i]);
findCombination(result, combinations, candidates, remain - candidates[i], i + 1);
combinations.remove(combinations.size()-1);
}
}
}


377. Combination Sum IV

只需求出所有可能组合的数量

Note:

1. C中无重复

2. C中的每一个数在组合中可出现任意次

如C = [1, 2, 3], T = 4, 则

可能的所有组合为
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

故结果为7.


解法

递推公式:comb[target] = sum(comb[target - nums[i]]) (0 <= i < nums.length && target >= nums[i]),comb[0] = 1。

递归,会超时,因为存在的大量重复计算(调用)

public class Solution {
public int combinationSum4(int[] nums, int target) {
if (target == 0) return 1;
int res = 0;
for (int i = 0; i < nums.length; i++) {
if (target >= nums[i]) {
res += combinationSum4(nums, target - nums[i]);
}
}
return res;
}
}


动态规划(从dp[0]到dp[target]都要计算,其中大部分可能都是不必要的)

public class Solution {
public int combinationSum4(int[] nums, int target) {
int [] dp = new int[target + 1];
dp[0] = 1;
for(int i = 1; i <= target; i++){
for(int j = 0; j < nums.length; j++){
dp[i] += (i - nums[j]) < 0 ? 0 : dp[i-nums[j]];
}
}
return dp[target];
}
}


动态规划+递归(可以将dp[]看作缓存),避免了重复计算和不必要的计算

public class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
Arrays.fill(dp, -1);
dp[0] = 1;
return helper(nums, target, dp);
}

private int helper(int[] nums, int target, int[] dp) {
//已计算过直接返回
if (dp[target] != -1)   return dp[target];

int res = 0;
for (int i = 0; i < nums.length; i++) {
if (target >= nums[i]) {
res += helper(nums, target - nums[i], dp);
}
}
dp[target] = res;
return res;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 算法 java