給你一個由 不同 整數組成的數組 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:
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
nums
中的所有元素 互不相同1 <= target <= 1000
這題一開始還試圖用之前遞歸的方法做,但發現這邊需要考慮不同順序。用動態規劃遞推來做會比較簡潔。
class Solution(object):
def combinationSum4(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
nums.sort()
dp = [0] * (target + 1) # dp[i]表示和爲i的不同組合數,初始化爲0
dp[0] = 1 # 總和爲0的組合方式只有一種,即空集
for i in range(1, target + 1):
for num in nums:
if i < num:
break
dp[i] += dp[i - num] # 所有和爲i-num的組合加上當前元素可以形成和爲i的新組合
return dp[target]
代碼雖然短,但對於很久沒寫dp的人來說還是需要理解一會的。。動態規劃通過構建一個解決方案的部分問題來解決整個問題,通常涉及填充一個或多個DP表(在這個問題中,是一個一維數組)。對於這個特定問題,DP數組的每個位置 i
代表了組成和爲 i
的不同組合數。
初始化
我們初始化 dp[0] = 1
。這意味着,總和爲0的組合方式只有一種,即不選擇任何數字(空集合)。這是動態規劃的基礎。
遞推關係
對於每個可能的 i
(從1到 target
),我們考慮所有可能的 nums
中的數字 num
,如果當前數字 num
小於或等於 i
,那麼 num
可以成爲一個潛在的組合部分。
我們的更新規則是 dp[i] += dp[i - num]
,它基於這樣的邏輯:
- 如果你已經知道了組成和爲
i - num
的所有可能的組合數(存儲在dp[i - num]
中),那麼每一種組合都可以通過添加num
來形成一個新的和爲i
的組合。 - 因此,你可以將這些新增的組合數加到
dp[i]
上。