问题描述:
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?
解题思路:
因为之前一直在做排列组合系列,所以这道题一拿到手,读完题,首先考虑的就是递归解法。
然后心里还在想,干嘛这么多重复的题ಠ_ಠ
事实又一次证明,我, 还是, 太, naive, 了!!!!!
虽然做的时候我感觉我会超时,但是真的超时了之后时满脸懵逼因为没有其他的好的思路。。
看了 http://www.cnblogs.com/grandyang/p/5705750.html 之后,思考了一段时间,才仿佛找到点感觉。
进入正题:
这道题用动态规划来解。
dp中存的是对于 i 来说,可能的排列,从1一直递增到target。
对于 i , 如果 i >= nums[j] (nums[j]在这里代表的是nums中的数字)
我们可以将nums中的数字排序,然后从小到大访问它们。
状态转移方程为 dp[i] += dp[i - nums[j]]
所以dp[0]要为1.
可以理解为,每次将nums[j]放在最左边然后能够得到的排序。
一开始我会想,不应该是乘吗?因为nums[j]在每个位置都有可能。
结果告诉我们并不是 :)
这肯定是有原因的!
我们可以这个排列抽象成两个部分,(实际上到了最基本的情况是只有这个数字自己)。 然后这两部分进行全排列就是它的全排列。
就nums[j] < i 的情况来讨论, 这个时候 i-nums[j] 也小于 i
如果nums[j] < i-nums[j], 那么nums[j] 在 i - nums[j] 中肯定出现过。
我感觉我要把自己说晕了,举个例子吧~
nums = [1, 2, 3]
这个时候dp[0] = 1
dp[1] = dp[1-1] = 1
dp[2] = dp[2-1] --->{1,1}
+dp[2-2] --->{2}
= 2
dp[3] = dp[3-1] --->{1, 1, 1}, {1, 2}
+dp[3-2] --->{2,1}
+dp[3-3]----->{3}
= 4
在dp[3]中我们可以看到对于含有2的组合中,2确实在每个位置都出现过了。
代码:
class Solution { public: int combinationSum4(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); vector<int> dp(target+1); dp[0] = 1; for(int i = 1; i <= target; i++){ for(int n : nums){ if(i < n){ break; } dp[i] += dp[i - n]; } } return dp.back(); } };