文章目錄
- 題目描述
- 思路分析
- 完整代碼
題目描述
給你一個 隻包含正整數 的 非空 數組 nums 。請你判斷是否可以将這個數組分割成兩個子集,使得兩個子集的元素和相等。
示例 1:
輸入:nums = [1,5,11,5]
輸出:true
解釋:數組可以分割成 [1, 5, 5] 和 [11] 。
示例 2:
輸入:nums = [1,2,3,5]
輸出:false
解釋:數組不能分割成兩個元素和相等的子集。
思路分析
在做這道題之前一定要先看 01背包理論基礎
這種題最難的不是寫代碼,也不是思路,而是怎麼模組化,要不是最近在練動态規劃,我都不一定能想到用01背包去做這個題。
題目和01背包的轉換:
題目給出一個數組nums,要求分成兩個子集,使他們相等,這裡要注意,隻能分成兩個子集。 是以問題轉化成,求一個子集 使其等于 sum(nums) // 2 == target。如果有這樣的子集 則傳回True 否則傳回False
背包容量就是 target, dp[j] 則代表 背包容量為j時能湊的最大的子集和為dp[j],最後如果 dp[target] == target 則就是找到了某個子集使其等于目标值。
這道題裡的物品重量=物品價值=數組值=nums[i]。
動規五步走;
1.确定dp下标含義:
dp[j] 表示背包容量為 j時,最大的子集和為dp[j],
2.确定遞推公式:
在問題轉換哪裡已經分析過了,直接拿傳統背包問題來轉換一下 就行。
遞推公式:dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
3.初始化dp
這裡的dp[j] 表示背包容量為j的最大子集和為dp[j]。
是以也就意味這容量能多大,我們初始化就得初始化多大的一維數組。
這裡要看題目給的提示。
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 100
是以最大應該是20000,而我們背包隻需要一半的容量,直接初始化10000個[0]的一維數組就行了。
完整代碼
class Solution:
def canPartition(self, nums: List[int]) -> bool:
if sum(nums) % 2 == 1:
return False
target = sum(nums) // 2
dp = [0] * 10000
# dp[i] 表示背包容量i 裡的最大子集是dp[i]
# 先物品,再背包,這裡就想那個二維的數組格子就行了。
for i in range(len(nums)):
for j in range(target,nums[i]-1,-1): # j表示背包容量,你的j必須大于目前周遊i的重量,才有往後的意義。
dp[j] = max(dp[j],dp[j-nums[i]]+nums[i])
return dp[target] == target