1. 程式人生 > >leetcode416分割等和子集——又一個揹包問題

leetcode416分割等和子集——又一個揹包問題

題目:

給定一個只包含正整數非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。

注意:

  1. 每個陣列中的元素不會超過 100
  2. 陣列的大小不會超過 200

示例 1:

輸入: [1, 5, 11, 5]

輸出: true

解釋: 陣列可以分割成 [1, 5, 5] 和 [11].

 首先可以看出如果陣列和為奇數,是無法分割的(自然數乘以二都是偶數)。

然後其中一個基本想法是BFS,這個數字nums【i】我可以選擇“加上”或者“不加”,

也就是雙重遞迴。

思路如下:

    def canPartition_(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        nums_sum=sum(nums)
        if nums_sum%2!=0:
            return False
        else:
            nums_sum//=2
        rec=[False]
        def search(nums,i,s=0):
            if i==len(nums) or s>nums_sum:
                return
            if nums[i]+s==nums_sum:
                rec[0]=True
                return
            else:
                search(nums,i+1,s)
                search(nums,i+1,s+nums[i])
        search(nums,0,0)
        return rec[0]

很可惜,這個方法只能AC不到一半的測試用例(可能C++或者Java會更多吧,畢竟沒有遞迴限制)。

那麼參考別人的答案後發現了用揹包問題來解決的辦法。

實際上我也想到過,但是無法轉化成對應程式碼。

    def canPartition(self,nums):
        nums_sum = sum(nums)
        if nums_sum % 2 != 0:
            return False
        else:
            nums_sum //= 2
        dp=[[0 for x in range(nums_sum+1)] for y in range(len(nums))]
        for i in range(nums[0],len(dp[0])):
            dp[0][i]=nums[0]
        for i in range(1,len(nums)):
            for j in range(nums[i],nums_sum+1):
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-nums[i]]+nums[i])
        return dp[-1][-1]==nums_sum

然而這個程式碼沒有通過,哈哈哈哈。

因為python太慢了,而我參考的java程式碼(寫法幾乎一樣)是可以通過的。

對於這種可以轉化為揹包問題的問題,還需要多加練習。