# 给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
#
# 题目数据保证答案符合 32 位整数范围。
#
#
#
# 示例 1:
#
#
# 输入:nums = [1,2,3], target = 4
# 输出:7
# 解释:
# 所有可能的组合为:
# (1, 1, 1, 1)
# (1, 1, 2)
# (1, 2, 1)
# (1, 3)
# (2, 1, 1)
# (2, 2)
# (3, 1)
# 请注意,顺序不同的序列被视作不同的组合。
#
#
# 示例 2:
#
#
# 输入:nums = [9], target = 3
# 输出:0
#
#
#
#
# 提示:
#
#
# 1 <= nums.length <= 200
# 1 <= nums[i] <= 1000
# nums 中的所有元素 互不相同
# 1 <= target <= 1000
#
#
#
#
# 进阶:如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
# Related Topics 动态规划
# 👍 379 👎 0
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [0] * (target+1)
dp[0] = 1
for i in range(1, target+1):
for num in nums:
if num <= i:
dp[i] += dp[i - num]
return dp[target]
# leetcode submit region end(Prohibit modification and deletion)
Success:
Runtime:48 ms, faster than 75.13% of Python3 online submissions.
Memory Usage:14.8 MB, less than 82.01% of Python3 online submissions.
错误解法——递归, 超时
看到这题时,第一反应是用递归:
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
count = 0
if target == 0:
count = 1
elif target > 0:
for num in nums:
count += self.combinationSum4(nums, target-num)
return count
果断超时。
用例:
[4,2,1], 32
本地跑了很久,得到结果是:
39882198
动态规划
递归之所以超时,是因为递归层数太深,已经有的知识没有重复利用。
记录已有信息,从底向上计算,即用到动态规划法。具体来说,该问题属于完全背包问题,即放置的物品可重复使用。
用 dp[i] 表示target为i时的所有组合数,考虑该怎么各dp[k] (k < i) 推出dp[i]呢?
假设最后一个加入的数字是num,且加入num 之后可得到一个元素之和等于 i 的排列,那么就可以把dp[i-num]种组合都累加到最终结果中。求出所有的 dp[i−num] 之和,即等于dp[i]。
可得递推公式:
dp[i] = 1, i = 0
dp[i] = SUM(dp[i-num[k]]), 0 <= k < n, i > 0
dp[i] = 0,i < 0
有了递推公式,动态规划就基本完成了。