leetcode-动态规划【背包问题】

2023-11-18

背包问题篇:

基础背包:

416. 分割等和子集

1049. 最后一块石头的重量ii

494. 目标和

474. 一和零

完全背包:

518. 零钱兑换ii

377. 组合总和iv

70. 爬楼梯

322. 零钱兑换

279. 完全平方数

139. 单词拆分

多重背包:


0-1背包:(所有元素只能放入一次)

n件物品和最大承受重量为w的背包,其中第i件物品的重量是weight[i],得到的价值是value[i],每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

1. 确定dp数组以及下标的含义

dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。i:物品编号,j:背包容量,dp[i][j]:价值总和

2. 确定递推公式

  • 不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同。)
  • 放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值

递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

3. dp数组初始化

dp[i][0]:背包容量为0因此价值总和为0

dp[0][j]:存放物品0的时候背包价值总和,当j<weight[0]价值总和为0,其余情况价值总和为value[0]

4. 确定遍历顺序:先遍历物品/背包重量

5. 举例推导dp数组

416. 分割等和子集

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if sum(nums) % 2: return False
        # 要求找到元素和为sum/2的子集
        target = sum(nums) // 2
        # dp[i][j]代表可装物品为0-i,背包容量为j的情况下,背包内容量的最大价值(最大子集和)
        dp = [[0 for _ in range(target+1)] for _ in range(len(nums))]
        # 背包容量为0且只能放入nums[i]的情况下背包最大价值(最大子集和)
        for j in range(nums[0],target+1):
            dp[0][j] = nums[0]
        # 递推公式(每行从左到右遍历)
        for i in range(1, len(nums)):
            for j in range(1, target+1):
                # 当背包不能容纳nums[i]时
                if j < nums[i]:
                    dp[i][j] = dp[i-1][j]
                # 当背包可以容纳nums[i]时
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-nums[i]] + nums[i])
        return dp[-1][-1] == target

使用滑动数组:

class Solution(object):
    def canPartition(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        if not nums or sum(nums) % 2: return False
        target = sum(nums) // 2
        # 滑动数组(因为只需要保留上一行的值因此可以使用一维数组)
        dp = [0 for _ in range(target+1)]
        for i in range(len(nums)):
            for j in range(target, nums[i]-1, -1):
                dp[j] = max(dp[j], dp[j-nums[i]] + nums[i])
        return dp[-1] == target

1049. 最后一块石头的重量ii

class Solution(object):
    def lastStoneWeightII(self, stones):
        """
        :type stones: List[int]
        :rtype: int
        """
        # 将stones分为重量差不多的两堆
        target = sum(stones) // 2
        # dp设为滑动数组,dp[j]存储最接近重量j其不超过的石头总重量
        dp = [0 for _ in range(target+1)]
        # 遍历stones
        for i in range(len(stones)):
            for j in range(target, stones[i]-1, -1):
                dp[j] = max(dp[j], dp[j-stones[i]]+stones[i])
        return sum(stones)-2*dp[-1]

494. 目标和

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        if len(nums) == 1 and nums[0] != target and nums[0] != -1 * target:
            return 0
        sum_nums = sum(nums)
        if target > sum_nums or target < -1 * sum_nums: return 0
        # dp[][sum_nums]为中心点
        dp = [[0 for _ in range(2*sum_nums+1)] for _ in range(len(nums))]
        for j in range(2*sum_nums+1):
            if abs(j - sum_nums) == nums[0]:
                if nums[0] == 0: dp[0][j] = 2
                else: dp[0][j] = 1
        for i in range(len(nums)-1):
            for j in range(2*sum_nums+1):
                if dp[i][j] == 0: continue
                dp[i + 1][j - nums[i + 1]] += dp[i][j]
                dp[i + 1][j + nums[i + 1]] += dp[i][j]
        return dp[-1][target+sum_nums]

第二种方法:

假设nums = [3,1,2,5,4],此时选3和1前面的符号为加号,其余为减号,那么此时加法获得的和为3+1=4,减法获得的和为2+5+4=11,也可以通过sum(nums)-3-1=15-3-1=11获得。以此类推,设加法获得的和为x,则减法获得的和为(sum-x),问题转化满足x-(sum-x)=target / x=(sum+target)/2有几种方案。

class Solution(object):
    def findTargetSumWays(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        sum_nums = sum(nums)
        # 注意边界条件
        if abs(target) > sum_nums or (sum_nums + target) % 2 == 1: return 0
        bagSize = (sum_nums + target) // 2
        dp = [0] * (bagSize + 1)
        dp[0] = 1
        for i in range(len(nums)):
            for j in range(bagSize, nums[i] - 1, -1):
                dp[j] += dp[j - nums[i]]
        return dp[bagSize]

474. 一和零

dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

class Solution(object):
    def findMaxForm(self, strs, m, n):
        """
        :type strs: List[str]
        :type m: int
        :type n: int
        :rtype: int
        """
        # dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]
        dp = [[0 for _ in range(n+1)] for _ in range(m+1)]
        for str in strs:
            onenum = str.count('1')
            zeronum = str.count('0')
            for i in range(m, zeronum-1, -1):
                for j in range(n, onenum-1, -1):
                    dp[i][j] = max(dp[i][j], dp[i-zeronum][j-onenum] + 1)
        return dp[m][n]

完全背包:(元素可以重复放入)

518. 零钱兑换ii

class Solution(object):
    def change(self, amount, coins):
        """
        :type amount: int
        :type coins: List[int]
        :rtype: int
        """
        # dp[i][j]表示coins[i]的面值加入排列后,总和为amount的组合数
        dp = [0 for _ in range(amount+1)]
        dp[0] = 1
        for i in range(len(coins)):
            for j in range(coins[i], amount+1):
                dp[j] += dp[j-coins[i]]
        return dp[-1]

377. 组合总和iv

class Solution(object):
    def combinationSum4(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        dp = [0 for _ in range(target+1)]
        dp[0] = 1
        for j in range(target+1):
            for i in range(len(nums)):
                if j-nums[i] >= 0:
                    dp[j] += dp[j-nums[i]]
        return dp[-1]

70. 爬楼梯

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        dp = [0 for _ in range(n+1)]
        dp[0] = 1
        for j in range(n+1):
            for step in range(1,3):
                if j - step >= 0:
                    dp[j] += dp[j-step]
        return dp[-1]

322. 零钱兑换

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp = [amount + 1] * (amount + 1)
        dp[0] = 0
        for coin in coins:
            for j in range(coin, amount + 1):
                dp[j] = min(dp[j], dp[j - coin] + 1)
        if dp[amount] < amount + 1:
            return dp[amount]
        else:
            return -1

279. 完全平方数

class Solution(object):
    def numSquares(self, n):
        """
        :type n: int
        :rtype: int
        """
        square, i = [], 1
        while i**2 <= n:
            square.append(i**2)
            i += 1

        dp = [n+1] * (n+1)
        dp[0] = 0
        for i in range(len(square)):
            for j in range(square[i], n+1):
                dp[j] = min(dp[j], dp[j-square[i]]+1)
        if dp[n] > n+1:
            return -1
        else:
            return dp[n]

139. 单词拆分

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        # dp[j]=1即截至此处s[:j+1]可划分,dp[j]=0即不可划分
        dp = [0 for _ in range(len(s)+1)]
        dp[0] = 1
        for j in range(1, len(s)+1):
            for word in wordDict:
                if j >= len(word):
                    dp[j] = dp[j] or (dp[j - len(word)] and word == s[j - len(word):j])
        return dp[-1] == 1

多重背包:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

leetcode-动态规划【背包问题】 的相关文章

随机推荐

  • matlab求傅里叶级数展开式_连续时间的傅里叶级数

    如果信号x t 是周期信号 那么对于所有t 存在一个最小正数T 使得x t x t T 其中 T 为这个周期信号的最小正周期 根据周期函数的周期性 x t x t N T N为整数 称为这个信号的基波频率 周期信号x t 也可以用周期复指数
  • 2020年全国高校计算机能力挑战赛初赛java语言解答

    题目1 统计从1到N的整数中 所有立方值的平方根为整数的数的格式 输入说明 整数N N lt 10000 输出说明 符合条件的数的个数 如4 3 64 8 2 输入样例 10 输出样例 3 说明 样例中符合条件的3个数是1 4 9 publ
  • Redis系列之安装配置

    前言 缓存Redis的讲解 作为第一个开篇文章 我们不谈高深的东西 从以下几个方面介绍下Redis 简介 安装 配置 启动 OK 下面我们就开始今天的缓存之旅吧 什么是Redis Redis是以Key value形式存储 和传统的关系型数据
  • Itext7填充PDF表单中文无法显示,‘凉’不显示问题

    Itext7填充PDF表单中文无法显示 凉 不显示问题 添加依赖
  • C#使用Sqlite总结

    1 下载Sqlite的dll 页面地址 http system data sqlite org index html doc trunk www downloads wiki 基于本项目的版本 下载Setups for 32 bit Win
  • C++11中std::shared_future的使用

    C 11中的std shared future是个模板类 与std future类似 std shared future提供了一种访问异步操作结果的机制 不同于std future std shared future允许多个线程等待同一个共
  • json-server -g报错

    在vscode终端报 在系统上禁止运行脚本 的话 在下面输入set ExecutionPolicy RemoteSigned 前提是你是以管理员模式运行vscode 然后重新输入 json server v即可
  • 低代码?未来会代替如今的代码吗?

    一 前言 如果选择用一个关键词来代表即将过去的2020年 我相信所有人都会认同是 新冠 疫情来得太快就像龙卷风 短短数月就阻断了全世界范围内无数人与人之间的物理连接 但好在 我们已经全面迈入互联网时代 N95口罩再厚 也阻挡不了信息比特流的
  • Translation Lookaside Buffer (TLB)

    CPU每次访问虚拟内存 虚拟地址都必须转换为对应的物理地址 从概念上说 这个转换需要遍历页表 页表是三级页表 就需要3次内存访问 就是说 每次虚拟内存访问都会导致4次物理内存访问 简单点说 如果一次虚拟内存访问对应了4次物理内存访问 肯定比
  • 如何访问WEB-INF文件夹下的jsp文件

    我们都知道不能直接访问WEB INF文件夹下的jsp文件 那应该怎样访问呢 首先 WEB INF目录是Java WEB应用的安全目录 客户端无法访问 只有服务端可以访问 然后 为什么要这么设计 这样做的初衷是在WEB INF文件夹下放一些不
  • VScode使用PlatformIO IDE时PIO Home一直loading的问题

    近来刚接触 Arduino 想做个小项目 网上都都说 Arduino 自带的IDE不人性化 推荐的是用 VScode搭配 PlatformIO 但是这个插件非常不稳定 各种坑 有的时候安装 Library 点击了 Add 以后会一直转 等半
  • 汇编实验(循环程序设计)(排序以及找非负数)

    这里的排序 用的是冒泡排序 首先 先是说一下找非负数的想法 负数 TEST 80H 之后不为0 我们可以用这个性质来做 1 FIND POSITIVE NUMBER LEA SI FIRST LEA DI SECOND MOV CX N L
  • pg数据库日志 linux,PostgreSQL删除pg_xlog日志

    PostgreSQL的pg xlog下有大量日志 空间不足 如何删除 Darren1 postgres usr local pgsql data pg xlog gt ls 000000010000000000000008 00000028
  • Python调试工具pdb使用详解

    Python调试工具pdb使用详解 1 前言 2 参考文档 3 pdb简介 4 pdb使用命令行调试 4 1 举例代码 4 2 调试器命令 4 2 1 进入pdb调试模式 4 2 2 帮助指令 4 2 3 控制程序执行 4 2 4 设置断点
  • python数据驱动库_Python3

    1 DDT简介 Data Driven Tests DDT 即数据驱动测试 它允许您通过不同的测试数据来运行同一个测试用例 使它作为多个测试用例出现 其官方文档给出的定义如下 DDT Data Driven Tests allows you
  • 利用MATLAB&C语言生成&读取.dat文件

    利用MATLAB C语言生成 读取 dat文件 MATLAB生成 dat文件 MATLAB读取 dat文件 方式一 方式二 C语言生成 dat文件 C语言读取 dat文件 注意事项 有时候 需要在matlab或c语言编程环境中写入或读取 d
  • Linux Socket 事件触发模型 epoll 示例 这里会写一个用C语言的TCP服务器的完全实现的简单程序

    背景介绍 通常的网络服务器实现 是对每一个连接使用一个单独的线程或进程 对高性能应用而言 由于需要同时处理非常多的客户请求 所以这种方式并不能工作得很好 因为诸如资源使用和上下文切换所需的时间影响了在一时间内对多个客户端进行处理 另一个可选
  • window怎么下载和使用nginx

    希望下面的东西对你有帮助 我们一起学习 一起加油 1 首先去官网下载 http nginx org en download html 2 下载后解压到指定文件夹 如图 3 启动negix有如下种 1 双击nginx应用程序即可 闪烁两下 即
  • FIddler之Fiddler移动端抓包

    前言 笔者今天的这篇文章呢 想使用通俗易懂的话语 让大家明白以下内容 什么是抓包哪些场景需要用到抓包Fiddler抓包的原理怎样使用Fiddler进行移动端抓包 一 抓包 包 Packet 是TCP IP协议通信传输中的数据单位 一般也称
  • leetcode-动态规划【背包问题】

    背包问题篇 基础背包 416 分割等和子集 1049 最后一块石头的重量ii 494 目标和 474 一和零 完全背包 518 零钱兑换ii 377 组合总和iv 70 爬楼梯 322 零钱兑换 279 完全平方数 139 单词拆分 多重背