class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
#dp[i]代表当target为i的时候组合个数
#假如是5
#4的组合数+1
#3的组合数+2
#2的组合数+3
#1的组合数+4
dp = [0]*(target+1)
dp[0] = 1
for i in range(1,target+1):
for num in nums:
if i>=num:
dp[i]+=dp[i-num]
return dp[-1]
#回溯直接超时了
# if min(nums)>target:
# return 0
# res = []
# def huisu(index,res,path):
# if sum(path)==target:
# res.append(0)
# return
# if sum(path)>target or nums[index]>target:
# return
# for i in range(len(nums)):
# path.append(nums[i])
# huisu(0,res,path)
# path.pop()
# path = []
# huisu(0,res,path)
# return len(res)
回溯算法完全暴力出超时,因此使用背包的思想,从动态转移的思路去求解这个问题
定义dp[i]表示和为i的组合个数,那么这个dp[i]怎么求呢。举个例子,比如i是5,如果要找和为5的组合,
我们可以用和为1的组合加上一个4
或者用和为2的组合加上3
或者用和为3的组合加上2
或者用和为4的组合加上1
而和为1,2,3,4的组合个数分别是dp[1],dp[2],dp[3],dp[4]。
所以和为5的组合个数就是他们几个的和,也就是dp[5]=dp[1]+dp[2]+dp[3]+dp[4];
但这里会有个问题,假如数组nums中没有2,我们是没法用和为3的组合加上2的,因为这里根本就没有2可选。那我们能选的数字有哪些呢,其实就是数组nums中元素。
所以上面的推理我们再来改一下
如果要求dp[i]
我们可以用和为i-nums[0]的组合再加上nums[0]
或者用和为i-nums[1]的组合再加上nums[1]
或者用和为i-nums[2]的组合再加上nums[2]
………
所以dp[i]的组合个数就是他们的累加,也就是dp[i]=dp[i-nums[0]]+dp[i-nums[1]]+……。
但这里还要注意一点,就是i-nums[j]不能小于0。