1+ #思路
12
2- 和之前个回溯法的各个总和串起来一波,本题用回溯稳稳的超时
3+ 本题题目描述说是求组合,但又说是可以元素相同顺序不同的组合算两个组合,其实就是求排列!
4+
5+ 弄清什么是组合,什么是排列很重要。
6+
7+ 大家在学习回溯算法系列的时候,一定做过这两道题目[ 回溯算法:39.组合总和] ( https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw ) 和[ 回溯算法:40.组合总和II] ( https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ )
8+
9+ 大家会感觉很像,但其本质是本题求的是排列总和,而且仅仅是求排列总和的个数,并不是把所有的排列都列出来。
10+
11+ 如果本题要把排列都列出来的话,只能使用回溯算法爆搜。
12+
13+
14+ * 确定dp数组以及下标的含义
15+
16+ dp[ i] : 凑成目标正整数为i的组合个数为dp[ i]
17+
18+ * 确定递推公式
19+
20+ dp[ i] (考虑nums[ j] )可以由 dp[ i - nums[ j]] (不考虑nums[ j] ) 推导出来。
21+
22+ 因为只要得到nums[ j] ,排列个数dp[ i - nums[ j]] ,就是dp[ i] 的一部分。
23+
24+ 所以递归公式: dp[ i] += dp[ i - nums[ j]] ;
25+
26+ * dp数组如何初始化
27+
28+ 因为递推公式dp[ i] += dp[ i - nums[ j]] 的缘故,dp[ 0] 要初始化为1,这样递归其他dp[ i] 的时候才会有数值基础。
29+
30+ 非0下标的dp[ i] 初始化为0,这样才不会影响dp[ i] 累加所有的dp[ i-nums[ j]]
31+
32+ * 确定遍历顺序
33+
34+ 个数可以不限使用,这是一个完全背包,且得到的集合是排列(需要考虑元素之间的顺序)。
35+
36+ 所以将target放在外循环,将nums放在内循环,内循环从前到后遍历。
37+
38+ C++代码如下:
339
440```
541class Solution {
@@ -19,28 +55,9 @@ public:
1955};
2056```
2157
58+ C++测试用例有超过两个树相加超过int的数据,所以需要在if里加上dp[ i] < INT_MAX - dp[ i - num] 。
2259
23- C++测试用例有超过两个树相加超过int的数据
24- 超限的情况
60+ 但java就不用考虑这个限制,我理解java里的int也是四个字节吧,也有可能leetcode后台对不同语言的测试数据不一样。
2561
2662
27- 一些题解会直接用ull usigned long long
2863
29- java 也是四个字节,理论上没有差别,可能后台java和C++测试用例不同,bug.....
30- ```
31- class Solution {
32- public:
33- int combinationSum4(vector<int>& nums, int target) {
34- vector<int> dp(target + 1, 0);
35- dp[0] = 1;
36- for (int i = 0; i <= target; i++) {
37- for (int num : nums) {
38- if (i - num >= 0 && dp[i] < INT_MAX - dp[i - num]) {
39- dp[i] += dp[i - num];
40- }
41- }
42- }
43- return dp[target];
44- }
45- };
46- ```