Update
This commit is contained in:
@@ -1,5 +1,41 @@
|
||||
# 思路
|
||||
|
||||
和之前个回溯法的各个总和串起来一波,本题用回溯稳稳的超时
|
||||
本题题目描述说是求组合,但又说是可以元素相同顺序不同的组合算两个组合,其实就是求排列!
|
||||
|
||||
弄清什么是组合,什么是排列很重要。
|
||||
|
||||
大家在学习回溯算法系列的时候,一定做过这两道题目[回溯算法:39.组合总和](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)和[回溯算法:40.组合总和II](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)
|
||||
|
||||
大家会感觉很像,但其本质是本题求的是排列总和,而且仅仅是求排列总和的个数,并不是把所有的排列都列出来。
|
||||
|
||||
如果本题要把排列都列出来的话,只能使用回溯算法爆搜。
|
||||
|
||||
|
||||
* 确定dp数组以及下标的含义
|
||||
|
||||
dp[i]: 凑成目标正整数为i的组合个数为dp[i]
|
||||
|
||||
* 确定递推公式
|
||||
|
||||
dp[i](考虑nums[j])可以由 dp[i - nums[j]](不考虑nums[j]) 推导出来。
|
||||
|
||||
因为只要得到nums[j],排列个数dp[i - nums[j]],就是dp[i]的一部分。
|
||||
|
||||
所以递归公式: dp[i] += dp[i - nums[j]];
|
||||
|
||||
* dp数组如何初始化
|
||||
|
||||
因为递推公式dp[i] += dp[i - nums[j]]的缘故,dp[0]要初始化为1,这样递归其他dp[i]的时候才会有数值基础。
|
||||
|
||||
非0下标的dp[i]初始化为0,这样才不会影响dp[i]累加所有的dp[i-nums[j]]
|
||||
|
||||
* 确定遍历顺序
|
||||
|
||||
个数可以不限使用,这是一个完全背包,且得到的集合是排列(需要考虑元素之间的顺序)。
|
||||
|
||||
所以将target放在外循环,将nums放在内循环,内循环从前到后遍历。
|
||||
|
||||
C++代码如下:
|
||||
|
||||
```
|
||||
class Solution {
|
||||
@@ -19,28 +55,9 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
C++测试用例有超过两个树相加超过int的数据,所以需要在if里加上dp[i] < INT_MAX - dp[i - num]。
|
||||
|
||||
C++测试用例有超过两个树相加超过int的数据
|
||||
超限的情况
|
||||
但java就不用考虑这个限制,我理解java里的int也是四个字节吧,也有可能leetcode后台对不同语言的测试数据不一样。
|
||||
|
||||
|
||||
一些题解会直接用ull usigned long long
|
||||
|
||||
java 也是四个字节,理论上没有差别,可能后台java和C++测试用例不同,bug.....
|
||||
```
|
||||
class Solution {
|
||||
public:
|
||||
int combinationSum4(vector<int>& nums, int target) {
|
||||
vector<int> dp(target + 1, 0);
|
||||
dp[0] = 1;
|
||||
for (int i = 0; i <= target; i++) {
|
||||
for (int num : nums) {
|
||||
if (i - num >= 0 && dp[i] < INT_MAX - dp[i - num]) {
|
||||
dp[i] += dp[i - num];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[target];
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user