代码随想录训练营第42天 | 01背包问题● 416. 分割等和子集

本文详细介绍了01背包问题的二维数组和一维数组解法,涉及动态规划实现,以及如何将其应用到LeetCode的子集和问题。讨论了时间复杂度为O(n^2),空间复杂度分别为二维O(n)和一维O(1)。
摘要由CSDN通过智能技术生成

01背包问题

题目链接:01背包问题-代码随想录

解法:

解法分为二维数组和一维数组的。内容有点多,看题解吧。

二维数组:01背包问题-二维数组-代码随想录

一维数组:01背包问题-一维数组-代码随想录

边界条件:

时间复杂度:O(n^2)

空间复杂度:二维 O(n), 一维O(1)

def test_2_wei_bag_problem1(weight, value, bagweight):
    # 二维数组
    dp = [[0] * (bagweight + 1) for _ in range(len(weight))]

    # 初始化
    for j in range(weight[0], bagweight + 1):
        dp[0][j] = value[0]

    # weight数组的大小就是物品个数
    for i in range(1, len(weight)):  # 遍历物品
        for j in range(bagweight + 1):  # 遍历背包容量
            if j < weight[i]:
                dp[i][j] = dp[i - 1][j]
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])

    return dp[len(weight) - 1][bagweight]

if __name__ == "__main__":

    weight = [1, 3, 4]
    value = [15, 20, 30]
    bagweight = 4

    result = test_2_wei_bag_problem1(weight, value, bagweight)
    print(result)
def test_1_wei_bag_problem(weight, value, bagWeight):
    # 初始化
    dp = [0] * (bagWeight + 1)
    for i in range(len(weight)):  # 遍历物品
        for j in range(bagWeight, weight[i] - 1, -1):  # 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

    return dp[bagWeight]


if __name__ == "__main__":

    weight = [1, 3, 4]
    value = [15, 20, 30]
    bagweight = 4

    result = test_1_wei_bag_problem(weight, value, bagweight)
    print(result)

416. 分割等和子集

题目链接:https://leetcode.com/problems/partition-equal-subset-sum/

解法:

只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。因为只要有子集之和等于 sum / 2,那么剩下的子集一定也等于 sum / 2。

要使用的是01背包,因为元素我们只能用一次。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

1. 确定dp[i]的含义

dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

2. 确定递推公式

01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。

所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])。

最后遍历完毕后,如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,就返回True。

背包问题的思维链真的有点长,代码写出来,我已经不知道它为啥可以解决这个道题了...

边界条件:无

时间复杂度:O(n^2)

空间复杂度:O(n)

class Solution(object):
    def canPartition(self, nums):
        total_sum = sum(nums)
        if total_sum % 2 == 1:
            return False
        target_sum = total_sum / 2
        dp = [0] * (target_sum + 1)
        for num in nums:
            for j in range(target_sum, num-1, -1):
                dp[j] = max(dp[j], dp[j-num]+num)
        
        if dp[target_sum] == target_sum:
            return True
        return False
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值