zoukankan      html  css  js  c++  java
  • 416分割等和子集

    题目:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
    注意: 每个数组中的元素不会超过 100,数组的大小不会超过 200
    来源:https://leetcode-cn.com/problems/partition-equal-subset-sum/

    法一:动态规划

    思路:首先写状态转移方程的时候,如果采用类似312戳气球的方法,即由内到外,由小到大,是难以实现的,原因有二,一是假如题目中的数组元素有6个,则dp[1]即长度为1的子集有6个,dp[2]长度为2的子集有15个,dp[3]长度为3的子集有20个,从dp[1]到dp[2]状态转移的过程中无法实现。二是由于长度不等,难以写成dp数组的形式。说到底是因为,dp[i]定义成了长度为i的子集的和,而不同长度的子集间由于子集的个数不同,难以写出状态转移方程。

              由此定义dp[i]为nums中从0到i的子集的和,则dp[i+1]从dp[i]转移过来的时候,由于dp[i]的情况很多,由此确定需要二维数组来记录,二维数组的列用来记录所有的和,如果这个和存在记为True,否则为False。

    from typing import List
    class Solution:
        def canPartition(self, nums: List[int]) -> bool:
            n=len(nums)
            target=sum(nums)
            if(target%2!=0):
                return False
            target//=2
            dp=[[False]*(target+1) for _ in range(n)]
            # 设置边界条件非常重要,将第一列(即和为0的列)设置为True,
            dp[0][0]=True
            # 先遍历第一行
            for i in range(1,target+1):
                if(nums[0]==i):
                    dp[0][i]=True
                    break
            # 遍历其余行
            for i in range(1,n):
                for j in range(target+1):
                    # 如果当前的目标和值大于等于要遍历的值,则将目标和值减去当前值看上一行和为dp[i-1][j-nums[i]]的为True还是False
                    if(j>=nums[i]):
                        dp[i][j]=dp[i-1][j] or (dp[i-1][j-nums[i]])
                    # 否则说明目标值小于要遍历的值,直接等于上一行的结果
                    else:
                        dp[i][j]=dp[i-1][j]
                # 如果最后一列出现True了,说明存在组合成目标值的和.直接返回True
                # if dp[i][-1] == True:
                #     return True
            return dp[-1][-1]
    if __name__ == '__main__':
        duixiang = Solution()
        a = duixiang.canPartition([1, 5, 11, 5])
        print(a)
    View Code

    来源:https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/dong-tai-gui-hua-kong-jian-you-hua-zhu-xing-jie--2/

    法二:备忘录方法  非常巧妙

    思路:利用ans记录之前的计算结果,每次都和之前的求和后判别是否满足条件。

    class Solution:
        def canPartition(self, nums: List[int]) -> bool:
            target, remain = divmod(sum(nums), 2)
            if remain:  # 如果不能整除直接返回
                return False
            ans = {0}
            for i in nums:
                for j in list(ans): # 循环中会改变ans
                    j += i
                    if j == target:  # 提前结束
                        return True
                    ans.add(j)  # 之前的结果加当前数能得到的结果
            return False
    View Code

    ttt

  • 相关阅读:
    【POJ】【2420】A Star not a Tree?
    【BZOJ】【2818】Gcd
    【BZOJ】【2190】【SDOI2008】仪仗队
    【Vijos】【1164】曹冲养猪
    【BZOJ】【1430】小猴打架
    【BZOJ】【3611】【HEOI2014】大工程
    【转载】完全图的生成树
    【BZOJ】【2286】【SDOI2011】消耗战
    【POJ】【1061】/【BZOJ】【1477】青蛙的约会
    Codeforces VK Cup Finals #424 Div.1 A. Office Keys(DP)
  • 原文地址:https://www.cnblogs.com/xxswkl/p/12238206.html
Copyright © 2011-2022 走看看