【数据结构与算法】动态规划:解密“0-1背包问题”的真相!附LeetCode四大问题的实现

 【作者自述:记录学习笔记,既然写了就让更多的人看到吧!欢迎大家关注交流学习,一步一个脚印持续更新!

【更多推荐笔记】

【数据结构与算法】回溯算法:用“更复杂”的代码求解LeetCode“分割问题”,解释并模拟递归+回溯的遍历过程-优快云博客

【数据结构与算法】排序算法:一次学懂十大排序算法!-优快云博客

【数据结构与算法】深度揭示深度优先搜索与广度优先搜索的区别_在数组中的应用[附Leetcode中三大岛屿问题的Python求解]-优快云博客

【推荐系统】 揭秘 ‘读懂’ 用户心思的推荐系统工作原理!-优快云博客


目录

01 何为背包问题?

02 “0-1背包问题”的动态规划解题思路

03 LeetCode中的“0-1背包问题”

1、分割等和子集

2、最后一块石头的重量II

3、目标和

4、一和零


常见的背包问题可以分为“0-1背包问题”和“完全背包问题”两类,这也是面试当中会遇到的高频问题,本文主要介绍“0-1背包问题”。

01 何为背包问题?

02 “0-1背包问题”的动态规划解题思路

直接上结论!!!关于“0-1背包问题”的一般性分析总结如下:

03 LeetCode中的“0-1背包问题”

实践出真知!结合LeetCode上的四道题目深刻感受一下其中的变化无穷和巧妙之处吧!

1、分割等和子集


def can_partition(nums):
    """ 416.分割等和子集:0-1背包问题 """
    total = sum(nums)
    if total % 2 != 0:
        return False
    target = total // 2
    dp = [False] * (target + 1)  # 是否存在和为i的子集
    dp[0] = True  # 初始化,存在空集和为0
    for num in nums:
        for i in range(target, num - 1, -1):
            dp[i] = dp[i] or dp[i - num]  # 已经存在和为i的子集或者存在和为i-num的子集,加上当前数值便可组成和为i的子集
    return dp[target]
2、最后一块石头的重量II


def last_stone_weight(stones):
    """ 1049.最后一块石头的重量II: 0-1背包问题 """
    total = sum(stones)
    target = total // 2
    dp = [False] * (target + 1)  # 是否能凑成目标重量
    dp[0] = True
    for weight in stones:
        for i in range(target, weight - 1, -1):
            dp[i] = dp[i] or dp[i - weight]

    for i in range(target, -1, -1):
        if dp[i]:  # 从后往前只找到最大的那个可以凑成的重量就可
            return total - 2 * i
3、目标和

def find_target_sum_ways(nums, target):
    """ 494.目标和:0-1背包问题"""
    total = sum(nums)
    # 假设选择了若干个数要令其为负数,和为neg;那选择的正数的和为total-neg;
    # 则total-neg-neg=total-2*neg=target——>可得neg=(total-neg)//2
    # 该问题转化为数组中和为neg的子集有多少个
    if (total - target) % 2 != 0 or total < abs(target):
        return 0
    new_target = (total - target) // 2
    dp = [0] * (new_target + 1)
    dp[0] = 1  # 初始化和为0的子集有一个
    for num in nums:
        for i in range(new_target, num - 1, -1):
            dp[i] += dp[i - num]
    return dp[new_target]
4、一和零


def find_max_form(strs, m, n):
    """ 474.一和零: 0-1背包问题"""
    # 每个二进制字符串可以看作一个物品
    # m和n可以看作是背包容量
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    # 表示最多使用i个0和j个1的情况下最大子集的大小
    for c in strs:
        ones = c.count('1')
        zeros = c.count('0')
        for i in range(m, zeros - 1, -1):
            for j in range(n, ones - 1, -1):
                dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1)
    return dp[m][n]

以上便是本文全部内容,个人拙见,若有不当之处还请指出!欢迎大家一起交流,共同学习!

参考资料:https://programmercarl.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵南夏

牛马一个,打工不易!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值