给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

递归函数

这里我们新加入三个变量,start 记录当前的递归到的下标,out 为一个解,res 保存所有已经得到的解,每次调用新的递归函数时,此时的 target 要减去当前数组的的数,具体看代码如下:

c++

class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> out;
combinationSumDFS(candidates, target, 0, out, res);
return res;
}
void combinationSumDFS(vector<int>& candidates, int target, int start, vector<int>& out, vector<vector<int>>& res) {
if (target < 0) return;
if (target == 0) {res.push_back(out); return;}
for (int i = start; i < candidates.size(); ++i) {
out.push_back(candidates[i]);
combinationSumDFS(candidates, target - candidates[i], i, out, res);
out.pop_back();
}
}
};

递归改进

我们也可以不使用额外的函数,就在一个函数中完成递归,还是要先给数组排序,然后遍历,如果当前数字大于 target,说明肯定无法组成 target,由于排过序,之后的也无法组成 target,直接 break 掉。如果当前数字正好等于 target,则当前单个数字就是一个解,组成一个数组然后放到结果 res 中。

然后将当前位置之后的数组取出来,调用递归函数,注意此时的 target 要减去当前的数字,然后遍历递归结果返回的二维数组,将当前数字加到每一个数组最前面,然后再将每个数组加入结果 res 即可,参见代码如下:

c++

class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> res;
sort(candidates.begin(), candidates.end());
for (int i = 0; i < candidates.size(); ++i) {
if (candidates[i] > target) break;
if (candidates[i] == target) {res.push_back({candidates[i]}); break;}
vector<int> vec = vector<int>(candidates.begin() + i, candidates.end());
vector<vector<int>> tmp = combinationSum(vec, target - candidates[i]);
for (auto a : tmp) {
a.insert(a.begin(), candidates[i]);
res.push_back(a);
}
}
return res;
}
};

java

class Solution {

	List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
if (target <= 0) {res.add(new ArrayList<>());}
//先排序,排序后可以加剪枝
Arrays.sort(candidates);
dfs(new ArrayList<>(), candidates, 0, target, 0);
return res;
} public void dfs(List<Integer> list, int[] candidates, int sum, int target, int start) {
for (int i = start; i < candidates.length; i++) {
list.add(candidates[i]);
if ((sum + candidates[i]) == target) {
//此时tmpList 满足
List<Integer> tmpList = new ArrayList<>(list);
res.add(tmpList);
} if ((sum + candidates[i]) < target) {
dfs(list, candidates, sum + candidates[i], target, i);
} else {
list.remove(list.size() - 1);
//(sum+candidates[i]) > target,因为数组有序,后面一定不满足
break;
}
list.remove(list.size() - 1);
}
}
}

动态规划

我们也可以用迭代的解法来做,建立一个三维数组 dp,这里 dp[i] 表示目标数为 i+1 的所有解法集合。这里的i就从1遍历到 target 即可,对于每个i,都新建一个二维数组 cur,然后遍历 candidates 数组,如果遍历到的数字大于i,说明当前及之后的数字都无法组成i,直接 break 掉。否则如果相等,那么把当前数字自己组成一个数组,并且加到 cur 中。否则就遍历 dp[i - candidates[j] - 1] 中的所有数组,如果当前数字大于数组的首元素,则跳过,因为结果要求是要有序的。否则就将当前数字加入数组的开头,并且将数组放入 cur 之中即可,参见代码如下:

c++

class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<vector<int>>> dp;
sort(candidates.begin(), candidates.end());
for (int i = 1; i <= target; ++i) {
vector<vector<int>> cur;
for (int j = 0; j < candidates.size(); ++j) {
if (candidates[j] > i) break;
if (candidates[j] == i) {cur.push_back({candidates[j]}); break;}
for (auto a : dp[i - candidates[j] - 1]) {
if (candidates[j] > a[0]) continue;
a.insert(a.begin(), candidates[j]);
cur.push_back(a);
}
}
dp.push_back(cur);
}
return dp[target - 1];
}
};

LeetCode——39. 组合总和的更多相关文章

  1. Java实现 LeetCode 39 组合总和

    39. 组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字 ...

  2. [LeetCode] 39. 组合总和

    题目链接 : https://leetcode-cn.com/problems/combination-sum/ 题目描述: 给定一个无重复元素的数组 candidates 和一个目标数 target ...

  3. [leetcode] 39. 组合总和(Java)(dfs、递归、回溯)

    39. 组合总和 直接暴力思路,用dfs+回溯枚举所有可能组合情况.难点在于每个数可取无数次. 我的枚举思路是: 外层枚举答案数组的长度,即枚举解中的数字个数,从1个开始,到target/ min(c ...

  4. leetcode 39 组合总和 JAVA

    题目: 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制 ...

  5. LeetCode 39. 组合总和(Combination Sum)

    题目描述 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限 ...

  6. leetcode 39. 组合总和(python)

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的数字可以无限制重复被选 ...

  7. 【LeetCode】39. 组合总和

    39. 组合总和 知识点:递归:回溯:组合:剪枝 题目描述 给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数  ...

  8. Java实现 LeetCode 40 组合总和 II(二)

    40. 组合总和 II 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在 ...

  9. LeetCode 中级 - 组合总和II(105)

    给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只能使用一次. ...

随机推荐

  1. vscode点击ctrl键报错Request textDocument/definition failed.

    现象 用vscode写java代码的时候突然出现,修复问题点击Ctrl时,输出窗口就打日志,报错Request textDocument/definition failed. 我百度唯一的有用线索就是 ...

  2. SCHema学习

    <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http:/ ...

  3. VMware Tools 组件、配置选项和安全要求

  4. springboot启动不能加载数据库驱动Failed to determine a suitable driver class

    SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/G:/sharp/repo ...

  5. c语言查漏补缺

    getchar:执行getchar()函数时,首先从输入缓存区读取字符,直到输入缓存区为空时才等待从键盘继续输入.scanf()之间不要有printf操作. 逗号表达式 a= (++a,1,2),只取 ...

  6. ios之开源

    a http://code.cocoachina.com b http://code4app.com c http://www.oschina.net/ios/codingList/ d github ...

  7. 《ES6标准入门》(阮一峰)--10.对象的扩展

    1.属性的简洁表示法 ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法.这样的书写更加简洁. const foo = 'bar'; const baz = {foo}; baz // ...

  8. 使用Def文件导出Dll文件

    模块定义 (.def) 文件是包含一个或多个描述 DLL 各种属性的 Module 语句的文本文件.如果不使用 __declspec(dllexport) 关键字导出 DLL 的函数,则 DLL 需要 ...

  9. 被疯狂吐槽的iPhoneXR屏幕真如传言中的那么差吗?

    在双十一期间,最受果粉关注的电商平台不是天猫,也不是京东,而是拼多多!原因很简单,拼多多疯狂给出iPhone的各种超低价格,直接压制了竞争对手.以iPhone XR为例,依据容量不同,价格分别为558 ...

  10. 【ABP】从零开始学习ABP_入门介绍

    本文介绍自己入坑ABP的过程,一些ABP的相关文章.QQ群,以及ABP Zero示例项目的运行. 背景 作为一个半路出家学习编程的新人,之前工作中也断断续续写过一些代码,但底层核心一直没机会学习,所以 ...