第45-46天学习笔记——DP真题

  • 序列dp
    • 路径问题
      • 【DP】华为2023秋招-PCB印刷电路板布线(难题,好好理解)
        • BFS + 路径DP
          • 首先我们需要根据原矩阵,构建出每一个位置干扰值叠加的结果,得到一个新的矩阵grid_new。这里显然就是一个基于BFS计算层数的问题。
          • 在得到新的矩阵grid_new之后,问题就转变为,对grid_new构建一条从左上到右下的路径,每次只能够向右或向下移动,路径经过的点的总和需要最小。这是一个经典的路径DP问题,和LeetCode64、最小路径和完全一致。
          • 要特别注意这里的BFS方法,这是一种新的应用型的BFS,和模板不完全一样

  • 状态DP
    • 【DP】OPPO2023秋招提前批-小欧的卡牌
      • 这道题可以使用动态规划来解决。我们可以将每张卡牌看作一个状态,传统dp需要清晰 dp数组含义、状态转移方程、和初始化。
      • dp数组含义:
        • dp二维数组是一个大小为n*3的数组
        • 用dp[i][j]表示前i张卡牌中,向上的数字之和模3等于j的方案数。这里面j为0,1,2表示模3的余数。
      • 状态转移方程:对于第i张卡牌,它可以选择正面向上或者背面向上
        • 正面向上,此时dp[i][j] = dp[i-1][(j+3-a[i]%3)%3],即前i-1张卡牌中向上的数字之和模3等于(j+3-a[i]%3)%3的方案数。
        • 背面向上,此时dp[i][j] = dp[i-1][(j+3-b[i]%3)%3],即前i-1张卡牌中向上的数字之和模3等于(j+3-b[i]%3)%3的方案数。
        • 最终的答案即为dp[n][0],即前n张卡牌中向上的数字之和模3等于0的方案数。
      • 初始化:初始一些抽象开始的值,保证方程正确推进
        • dp数组的初始化是dp[0][0] = 1,即前0张卡牌中向上的数字之和模3等于0的方案数为1,其余的dp数组元素都为0。这是因为前0张卡牌中向上的数字之和为0,因此只有一种方案,即不选任何卡牌。
    • 【DP/贪心】字节跳动2023秋招-小红的 01 串
      • 状态DP法
        • 每一个位置都有染和不染两种情况,故可以用状态dp来解决问题。
        • 初始化n*2的二维dp数组,dp[i]表示考虑第i个字符的情况
          • dp[i][0]表示第i个字符染色,能得到的最多染色数目
          • dp[i][1]表示第i个字符不染,能得到的最多染色数目
        • 分为两种情况,即第i个字符和第i-1个字符不同 和 第i个字符和第i-1个字符不同
      • 也可以贪心地解决问题,因为对于每一个01或10子串,只能染色一个字符,因此可以通过字符串中01或10子串的个数来进行计算。
    • 【DP】米哈游2023秋招-米小游与魔法少女-奇运 (没看懂,再理解吧)
  • 背包DP
    • 【DP】Shein2023秋招提前批-零钱兑换
      • 注意,本题和LeetCode322.零钱兑换完全一致。属于经典的路径无关、求方法数的完全背包问题。
      • dp数组的含义是:dp[i]表示组成钱数i的最少货币数。
      • 状态转移方程为:dp[i] = min(dp[i], dp[i - arr[k]] + 1),其中arr[k]表示第k种面值的货币。
      • 初始化时,我们需要将dp[0]初始化为0,表示组成钱数0的最少货币数为0。对于其他的dp数组元素,我们需要将它们初始化为正无穷,表示它们暂时无法由给定的面值组成。
      • 具体处理过程如下:
        • 需要枚举每个钱数i和每个面值arr[j],判断是否可以用arr[j]来组成钱数i,如果可以,则更新dp[i]的值。
        • 具体来说,可以使用两层循环来实现枚举。外层循环枚举钱数i,从1到aim;内层循环枚举面值arr[j],从0到n-1。对于每个钱数i和每个面值arr[j],我们需要判断是否可以用arr[j]来组成钱数i,即判断i是否大于等于arr[j],如果是,则可以用arr[j]来组成钱数i,此时我们需要判断dp[i - arr[j]]是否为正无穷,如果不是,则可以用dp[i - arr[j]] + 1来更新dp[i]的值。最终,dp[aim]的值即为组成aim的最少货币数。
        • 需要注意的是,如果某个钱数i无法由给定的面值组成,则dp[i]的初始值应该为正无穷,表示无解
    • 【DP】华为2023秋招-开电动汽车回家过年
      • 每一个充电站都有选和不选两种状态,所以我们可以把题目看作是路径无关、求最少选择数的01背包。
      • dp数组的含义是什么?
        • dp数组是一个长度为(n+1)*(P+1)的二维矩阵,dp[i][j]表示来到第i个充电桩时,剩余电量为j,所需要的最少充电次数。
        • 特别地,dp[n]表示来到A城的结果。
      • 动态转移方程是什么?
        • 来到第i个充电桩时,假设剩余电量为j,距离下一个充电桩的距离为Ai+1 - Ai,即花费的电量为diff = a_list[i+1]-a_list[i]。
        • 如果选择充电,那么充电后的电量为min(j+b_list[i], P),即充电后电量不能超过最大电量。
          • 到达第i+1个充电桩时,剩余电量为nxt = min(j+b_list[i], P) - diff
          • 故动态转移方程为dp[i+1][nxt] = min(dp[i][j]+1, dp[i+1][nxt])
          • 注意,此处的+1表示在第i个充电桩处进行了多一次充电
        • 不选择充电
          • 到达第i+1个充电桩时,剩余电量为nxt = j - diff
          • 故动态转移方程为dp[i+1][nxt] = min(dp[i][j], dp[i+1][nxt])
      • 注意,上述两个动态转移方程成立的条件是nxt >= 0,即从第i个充电桩开往第i+1个充电桩时,剩余电量不能够耗尽。

      • dp数组如何初始化?
        • 在起点出发时,电量为满电,到达第0个充电站时,剩余电量为P-a_list[0],此时最少充电方法数为0次。故初始化dp[0][P-a_list[0]] = 0。对于其他位置,初始化为inf

  • 作业
    • 注意回文子串和回文子序列的区别

    • LeetCode 5、最长回文子串
      • i到j之间是否为回文子串取决于i+1和j-1之间是否为回文子串

      • 因此,dp数组定义为:dp[i][j]表示字符串s第i个字符和字符串s第j个字符之间的子串是否是回文子串
      • dp数组初始化:因为i始终在j的左侧,所以i<j的部分就不考虑了,同时一开始i和j是在数组的最右端的

      • 整体代码

    • LeetCode 516、最长回文子序列
      • dp数组定义为:设置数组 dp,用来存储字符串 s 的最长的回文子序列的长度
      • 初始化:dp[i][i] 表示字符串 s 第 i 个字符和字符串 s 第 i 个字符之间的最长的回文子序列的长度,此时,这个区间的字符只有一个,最长的回文子序列的长度为 1
      • 转移方程:
        • 如果i和j位置的字符相同,dp[i][j] = dp[ i + 1 ][ j - 1 ] + 2
        • 如果i和j位置的字符不同,1、去掉头以后的区间的最长的回文子序列的长度,即 dp[i + 1][j] ; 2、去掉尾以后的区间的最长的回文子序列的长度,即 dp[i][j - 1] ,二者取最大值
      • 整体代码

    • 【DP】得物2023秋招-Cheems的漂亮糖葫芦
      • 回文子串的问题,通常也可以使用DP方法来完成。虽然在本题中不能显著地减少复杂度,但用DP方法解决回文子串问题是必须要掌握的。本题可以视为LeetCode5. 最长回文子串的简单版。
    • 【DP】用友2023秋招-最佳面试策略
    • 【DP】Bilibili2023秋招-两个字符串的最小ASCII删除和 (LeetCode712. 两个字符串的最小ASCII删除和原题。属于经典的LCS问题的变式)
      • DP数组定义
        • 构建大小为(n+1)*(m+1)的dp数组
        • dp[i][j]表示,令以s1[i-1]为结尾的字串s1[:i] ,以s2[j-1]为结尾的字串s2[:j] ,两者完全相同所需删除字符的ASCII值的最小和
      • 转移方程
        • 若两个结尾字符不相等,则在以下三种情况中挑出最小值赋值给dp[i][j]
          • 1. 同时删除s1[i-1]和s2[j-1],那么从dp[i-1][j-1]转移过来,为ord(ch1) + ord(ch2) + dp[i-1][j-1]
          • 2. 只删除s1[i-1],保留s2[j-1],那么从dp[i-1][j]转移过来,为ord(ch1) + dp[i-1][j]
          • 3. 只删除s2[j-1],保留s1[i-1],那么从dp[i][j-1]转移过来,为ord(ch2) + dp[i][j-1]
        • 若两个结尾字符相等,则无需做任何删除
          • 直接在dp[i-1][j-1]中延长过来即可
      • 整体代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值