• 动态规划题目总结


    本篇总结涉及的题目包括两道经典的动规题目(来自头条题库)及剑指offer中的所有(10道)动归题目(题目分类链接见文末)。

    动规问题是算法中比较经典并且比较难的一类算法,通常解决该类问题的思路是:

    ① 假设状态(从问题中抽象出dp[i]或者dp[i][j]的含义)

    ② 找出状态转移方程(待求解问题和子问题的关系)

    ③ 确定边界(一般问题都有初始值,或者需要考虑特殊情况)

    ④ 确定实现方式(自上而下或者自下而上,本篇博客都采取的是自下而上的实现方式,因为该方法更加高效)

    经典题1:编辑距离

    题目描述:给定两个字符串,允许增加,删除或者修改字符来使得两个字符串一致的最少操作次数。

    假设状态:dp[i,j]代表字符串s1的前i个字符和字符串s2的前j的字符的编辑距离

    状态转移方程及边界:

     代码实现:

     理解并写出状态转移之后,代码实现就比较容易了,考察代码能力。首先可以先画出这个二维表,长和宽分别为两个字符串的长度m和n。由于dp[i,j]依赖于dp[i-1,j-1], dp[i-1,j]和dp[i,j-1],也就是一个元素依赖于其左边上边和左上角的三个元素,因此只需填充初始值,接着按行计算就可以了,填完表后,我们要返回的值就是dp[-1][-1],也就是最右下角的值。后续代码实现类似,不详细展开,具体代码实现见文末。

    经典题2:最长回文子串

    题目描述:一个字符串中最长的具有回文特征的子串。(子串是连续的,子序列是可以不连续的)

    假设状态:dp[i,j]代表dp[i]到dp[j]是否为回文串

    状态转移方程及边界:

    dp[i,j]=dp[i+1,j-1] and (dp[i]==dp[j])

    实现注意:对角线为T,左下三角为F。因为依赖左下角元素,所以需要计算出连续2个字符的回文情况才可以用状态转移计算其他的。

    下面前4道都是和Fibonacci数列相关的题目,2-4主要是问题抽象和思路转化。

    剑指1:Fibonacci数列

    题目描述:0,1,1,2,3,5,8,...

    假设状态:dp[i]代表第i个元素的值

    状态转移方程及边界:子问题非常明显,可以直接根据题意写出

    剑指2:矩形覆盖

    题目描述:n个2x1的矩形去覆盖2xn的矩形,有多少种覆盖方法

    假设状态:dp[i]代表当n为i的时候的方法数,因为每次可以竖着放一个或者横着放两个,所以有两种选择,只需考虑剩下的部分即可。当然另外一种方法是你写出前几个的方法数,找规律,但是如果没有特别明显的规律就不可行了。

    状态转移方程及边界:

    剑指3:青蛙跳台阶

    题目描述:n个台阶,每次跳1或2个,求跳法数。

    假设状态:dp[i]代表当n为i的时候的方法数

    状态转移方程及边界:

    剑指4:变态跳台阶

    题目描述:n个台阶,每次跳1/2/.../n个,求跳法数。

    假设状态:dp[i]代表当n为i的时候的方法数

    状态转移方程及边界:

    dp[1]=1, dp[2]=2

    dp[i]=dp[i-1]+dp[i-2]+...+dp[0]

    dp[i-1]=dp[i-2]+...+dp[0]

    所以dp[i]=2dp[i-1]=2i-1

    剑指5:连续子数组的最大和

    题目描述:一个数组中连续子数组和的最大值

    假设状态:这里比较难,要找到子结构。因为子数组的起始和末尾都可以不固定,这样子结构就是任意的。我们可以固定起始位置,实现如下图所示的子结构。

    dp[i]代表以nums[i]为结尾的连续子数组的和的最大值,最后再取dp数组中的最大值即所求。

    状态转移方程及边界:

     dp[0]=nums[0]

    剑指6:礼物的最大价值

    题目描述:一个数字矩阵,从左上角走到右下角路径和的最大值,只能向右或向下走。

    假设状态:dp[i,j]代表走到(i,j)时候获取的最大值。

    状态转移方程及边界:

    dp[i,j]=max(dp[i-1,j], dp[i,j-1])+Arr[i,j]

    剑指7:最长不含重复字符的子字符串

    假设状态:和上上道题目类似,dp[j]代表以str[j]结尾的不重复子串的最大长度。

    状态转移方程及边界:

    假设str[j]左边最近的满足str[i]=str[j]的字符str[i]:

    剑指8:丑数

    题目描述:只含因子2,3,5的数叫丑数,求第n个丑数。

    假设状态:dp[i]

    状态转移方程及边界:

    本题目需要一些数学推导来简化过程,否则也会超时

    剑指9:n个骰子的点数

    题目描述:掷n个骰子,向上面之和的所有概率

    假设状态:这个题首先可以化简为向上面之和出现的次数,因为最后只要除以6n即可。然后将少掷一个骰子剩下的骰子看作子问题。dp[i,j]代表投完i个骰子后,点数和为j的情况数。

    状态转移方程及边界:

    对于最后一个骰子,其值取1到6,然后考虑子问题,如果最后一个骰子为1(已经确定),那么总情况数为dp[i-1,j-1],所以考虑6种情况:

    dp[i,j]=dp[i-1,j-1]+dp[i-1,j-2]+dp[i-1,j-3]+dp[i-1,j-4]+dp[i-1,j-5]+dp[i-1,j-6]

    (这个状态假设还是比较难的,所以最开始用自己的方法实现,然而超时了,详见代码)

    剑指10:构建乘积数组

    题目描述:求一个数组对应的乘积数组,其中一个数对应的乘积是原数组中除了该数之外其他数的积。

    实现思路如下:

    子问题就是不同长度的连续乘积,最后将两侧乘起来返回即可。

    Ref:

    剑指offer中算法题分类:https://github.com/CyC2018/CS-Notes/blob/master/notes/%E5%89%91%E6%8C%87%20Offer%20%E9%A2%98%E8%A7%A3%20-%20%E7%9B%AE%E5%BD%95.md

    自己的题解(可能偶尔有的题参考了别人的code,侵删):https://github.com/Cinderella0709/LeetcodePy/blob/main/DynamicProgramming.py

  • 相关阅读:
    MDK+VS+Eclipse的STM32库V3.5工程模板的建立(六)
    MDK+VS+Eclipse的STM32库V3.5工程模板的建立(一)
    MDK+VS+Eclipse的STM32库V3.5工程模板的建立(四)
    ognl.OgnlException: target is null for setProperty(null, "username", [Ljava.lang.String;@19af9e98)
    Hibernate联合主键Annotation
    struts2入门第一天配置环境
    为什么java的构造方法中this()或者super()要放在第一行
    几种解决IE6下PNG图片透明问题
    IE6解决min_height
    一个拖拽例子
  • 原文地址:https://www.cnblogs.com/pear-linzhu/p/14434583.html
Copyright © 2020-2023  润新知