[Leetcode解題] 416. Partition Equal Subset Sum
6 January 2024
medium
hashmap
dp
marked
題目
416. Partition Equal Subset Sum
給定一個矩陣,判定是否能將此矩陣分開成兩個子集(subsets),並且兩個子集的和相等。
解題思路
首先,子集(subset)和子矩陣(subarray)的差別在於,子集可以不連續,而子矩陣必須連續,所以此題所求的子集可以為不連續。
因為我們想將其一分為二,所以如果矩陣和為奇數,那一定不可被一分為二,而如果為偶數則有可能。
所以題目能被簡化成,如果為偶數,求矩陣中有沒有子集的和為原矩陣和的一半,有的為則得解。舉個例子來說,如果矩陣和為$100$,我們如果可以求得一子集和為$50$,則其他未被選中的數總和也為$50$,故得解。
若給定一個矩陣,以及一個目標數(target),若此矩陣中能找到一個子集總和為target,則回傳True,反之則回傳False。
我們可以使用dp來解這題,dp可以設計成:
dp[k][target] = dp[k-1][target] or dp[k-1][target-nums[k]]
也就是如果前(k-1)個數已經可以得到target,則前k個數也一定可以,若不行若前k-1個數可以得到(target-nums[k]),再加上第k個數nums[k]則可得到target。
此方法可行的一個前提是因為矩陣總和的target最大為$10000$,故可以直接創一個二維矩陣,但若範圍更大,則可以用$dict$來存會更節省空間。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
def partition(nums, target):
dp = [[False for i in range(target+1)] for j in range(len(nums))]
for i in range(len(nums)):
dp[i][0] = True
for i in range(1, len(nums)):
for t in range(1, target+1):
prev = dp[i-1][t]
if nums[i] > t:
dp[i][t] = prev
else:
dp[i][t] = prev or dp[i-1][t-nums[i]]
return dp[-1][-1]
total = sum(nums)
if total % 2 == 1:
return False
return partition(nums, total // 2)
時間複雜度
由於dp為一個$m \times n$的二維矩陣,$m$為原矩陣長度,而$n$為$target$,最大可為$100 \times 200 / 2$。