动态规划总结--01背包(未完待续)

0、什么样的题适合使用动态规划

如果某一问题有很多 重叠子问题,使用动态规划是最有效的
❓计算f(N)的时候需要f(N-1),也就是需要f(N-2),等等等,如果我们直接计算第n个的值,会导致前面的值被重复计算很多很多次
⭐️把前面的值记录下来

1、刷过的习题思路汇总

1️⃣509. 斐波那契数

  • 重叠子问题:计算第n个值需要第n-1和n-2的值
  • dp[i] 代表第i个数字的值
  • dp[0] = 0 dp[1] = 1
  • d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i] = dp[i-1] + dp[i-2] dp[i]=dp[i1]+dp[i2]

2️⃣70. 爬楼梯

  • 重叠子问题:爬到第n阶台阶的方法就是爬到第n-1阶台阶的方法(一步上来)➕ 爬到第n-2阶台阶的方法(两步上来)
  • 和斐波那契数一模一样

3️⃣746. 使用最小花费爬楼梯

  • 重叠子问题:爬到第n阶台阶的最少花费就是爬到第n-1阶台阶的最少花费加第n-1个台阶的花费(一步上来)和 爬到第n-2阶台阶的最少花费加第n-2个台阶的花费(两步上来)两者的最小值
  • dp[i]:到达第i阶台阶需要的最小花费
  • dp[0] = 0 dp[1] = 0
  • d p [ i ] = m i n ( d p [ i − 1 ] + c o s t [ i − 1 ] , d p [ i − 2 ] + c o s t [ i − 2 ] ) dp[i] = min(dp[i-1] + cost[i-1] , dp[i-2] + cost[i-2]) dp[i]=min(dp[i1]+cost[i1],dp[i2]+cost[i2])

4️⃣62. 不同路径

  • 重叠子问题:到(i,j)的路径要么从(i-1,j)要么从(i,j-1)两条路来,也就是说求到(i,j)的方法数就是到(i-1,j)的方法数 ➕ 到(i,j-1)的方法数
  • dp[i][j]表示从(0,0)到(i,j)有多少路径
  • 第一行和第一列都是1(只有一种方法)
  • d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + d p [ i − 1 ] [ j ] dp[i][j] = dp[i][j-1] + dp[i-1][j] dp[i][j]=dp[i][j1]+dp[i1][j]

5️⃣63. 不同路径 II(障碍物版本)

  • 初始化有点变化,当第一行或者第一列中出现障碍物,后面的值为0
  • 只有当(i,j)不是障碍物才会有值,否则就是0,代表到这个点的路径置零

6️⃣ 343. 整数拆分

  • 重叠子问题:求n的拆分乘积最大值?最简单的就是拆分成两个数 i i i ( n − i ) (n-i) (ni) 的乘积最大值,但是由于可以拆成更多的数,所以结果应该是拆分项 i i i ( n − i ) (n-i) (ni) 的拆分乘积最大值,这里其实就说明我们需要更小的整数拆分结果来得到n的整数拆分结果
  • dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。
  • dp[0] = 0 dp[1] = 0 dp[2] = 1
  • d p [ i ] = m a x ( d p [ i ] , ( i − j ) ∗ j , d p [ i − j ] ∗ j ) dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j}) dp[i]=max(dp[i],(ij)j,dp[ij]j)

7️⃣96. 不同的二叉搜索树

  • 背景了解 :二叉搜索树就是做变节点小于根节点,右边节点大于根节点。如果节点数为1,那么只有一种搜索树;两个节点,就有两种;三个节点,就是五种。在统计三个节点的时候发现,如果左\右子树是两个节点就是2种,一个节点就是1种
  • 重叠子问题:求n哥节点的二叉搜索树其实就是求左子树的二叉搜索树的种类数 加上 右子树的二叉搜索树的种类数,左字数的节点数量可以从1一直到n-1,一直累加就好了
  • dp[i]:节点为i的二叉树搜索树的种类数
  • dp[1] = 1 dp[2] = 2
  • d p [ i ] = d p [ i ] + d p [ j − 1 ] ∗ d p [ i − j ] dp[i] = dp[i] + dp[j-1] * dp[i-j] dp[i]=dp[i]+dp[j1]dp[ij]

8️⃣ 01背包问题

  • 问题描述 :有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大
  • 重叠子问题:每一个物品,有两种选择:“放或者不放
    • 如果放物品i,背包容量就变成w-weight[i],那么此时背包容量w的最大价值为value[i] + 背包容量为(w-weight[i])的最大价值(子问题)
    • 如果不放物品i,背包容量还是w,那么此时背包容量w的最大价值为背包容量为(w)的最大价值
  • 二维dp数组
    • dp[i][j]代表背包容量为j的情况下,从下标为[0, i]的物品里面任意取,能达到的最大价值
    • dp[0][x] = 0
    • d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − w e i g h t [ i ] ] + v a l u e [ i ] ) dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]) dp[i][j]=max(dp[i1][j],dp[i1][jweight[i]]+value[i])
    • 遍历顺序:物品:正序;背包容量:正序
  • 一维dp数组
    • dp[j]代表背包容量为j装的最大价值
    • dp[0] = 0
    • d p [ j ] = m a x ( d p [ j ] , d p [ j − n u m s [ i ] ] + n u m s [ i ] ) dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]) dp[j]=max(dp[j],dp[jnums[i]]+nums[i])
    • 遍历顺序:物品:正序[0,物品数量-1];背包容量:倒序[背包容量,物品i的重量,-1]
      9️⃣ 416. 分割等和子集
  • 题目:判断是否可以将正整数数组分割成两个子集,使得两个子集的元素和相等。
  • 思路
    • 数组中的每个元素就是物体, 价值和重量都输数值
    • 背包容量就是sum/2(不能整除就说明不能分割)
    • 判断是否可以选择一些物品(不重复),总和等于背包容量
    • dp[背包容量]代表背包容量下的背包能够放入的最大数值和,如果这个值等于sum/2就说明可以分割。
  • dp[j]代表背包容量为j装的最大数值和(价值)
  • d p [ j ] = m a x ( d p [ j ] , d p [ j − n u m s [ i ] ] + n u m s [ i ] ) dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]) dp[j]=max(dp[j],dp[jnums[i]]+nums[i])
  • 遍历顺序:数组:正序[0,数组长度-1];背包容量:倒序[背包容量,数值i,-1]

就相当于要凑一个背包容量为sum/2的背包。带入01问题就是,使用数值装进背包,

1️⃣0️⃣1049. 最后一块石头的重量 II

  • 题目:粉碎石头,使得剩下的重量最小
  • 思路 把石头分成两组重量相似的两组石头,这样剩下的石头重量最小
    • 物体就是石头,重量和价值都是石头重量
    • 背包容量就是sum/2
    • 选择一些石头(不重复)在背包容量范围内,放入石头的重量最大值(价值)
    • 基本上和分割等和子集一样但是,不是判断,而是两个子集相减
  • dp[j]:背包容量为j,能够放进去的最大石头重量(价值)
  • d p [ j ] = m a x ( d p [ j ] , d p [ j − s t o n e s [ i ] ] + s t o n e s [ i ] ) dp[j] = max(dp[j],dp[j-stones[i]]+stones[i]) dp[j]=max(dp[j],dp[jstones[i]]+stones[i])
  • 遍历顺序:石头:正序[0,石头数量-1];背包容量:倒序[背包容量,石头i重量,-1]

1️⃣1️⃣ 494. 目标和

  • 题目:正数数组通过不同元素前面加法或者减法,得到目标值的方法有多少种

  • 思路 通过公式推导,这个问题就是找到一些数的的和为(target+sum)/2,这样的方法有多少种

    • 物体就是数值,重量就是数值大小,因为问题不再是求装满物品的价值最大,而是组合最多,所以物品不需要价值属性了
    • 背包容量就是(sum+target)/2
  • dp[j]:填满j(包括j)这么大容积的包,有dp[j]种方法(注意不是最大价值了

  • d p [ j ] = d p [ j ] + d p [ j − n u m s [ i ] ] dp[j] = dp[j] + dp[j - nums[i]] dp[j]=dp[j]+dp[jnums[i]]

    • 对于物品i,有两种情况,装或者不装,装的话的方法数就变成了dp[j-nums[i]],不装就还是dp[j]
  • 遍历顺序:物品:正序[0,物品数量-1];背包容量:倒序[背包容量,数值大小,-1]

1️⃣2️⃣ 474. 一和零

  • 题目:给你一个二进制字符串数组 strs 和两个整数 m 和 n 。请你找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 。
  • 思路 相当于每个字符串有两个质量(0的数量和1的数量),背包也有两个容量
    • 物品 :每个字符串,重量为两个值分别是0的数量和1的数量,价值就是1(代表能装进去)
    • 背包容量 :两个,0的容量为m,1的容量为n
  • dp[i][j]代表0的容量为i,1的容量为j的背包能装的字符串的个数
  • d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , d p [ i − n u m 0 ] [ j − n u m 1 ] + 1 ) dp[i][j] = max(dp[i][j],dp[i-num_0][j-num_1]+1) dp[i][j]=max(dp[i][j],dp[inum0][jnum1]+1)
  • 遍历顺序:字符串:正序[0,字符串数量-1];背包容量(2个):倒序[背包容量,字符串的质量,-1]
  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

郭小儒

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值