动态规划题型总结

动态规划适用于子结构具备如下性质的问题:

  1. 重复子问题
  2. 最优子结构:问题的最优解所包含的子问题的解也是最优的(子问题的最优解一定包含在原问题的最优解之中)

解题的时候,画问题调用图,有助于获取递推式

  • 例子:编辑距离 https://baike.baidu.com/item/%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB/8010193?fr=aladdin

    dp_table(i,j)   --> dp_table(i,j+1)
        |        \          |
        |         \         |
        v          \        v
    dp_table(i+1,j) --> dp_table(i+1, j+1) [被重复计算]
    
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        #f(word1[i:n], word2[j:m]) = min{f(word1[i:n], word2[j+1:m]) + 1,
        #                                f(word1[i+1:n], word2[j:m]) + 1,
        #                                f(word1[i+1:n], word2[j+1:m]) + (word1[i] != word2[j])}
        if word1 == word2:
            return 0
        
        if word1 == '':
            return len(word2)
        if word2 == '':
            return len(word1)
    
        # ! bad version !
        # return min(1 + self.minDistance(word1, word2[1:]),
        #         1 + self.minDistance(word1[1:], word2),
        #         (1 if word1[0] != word2[0] else 0) + self.minDistance(word1[1:], word2[1:]))
    
        # ! correct version !
        len1 = len(word1)
        len2 = len(word2)
        dp_table = [[0 for _ in range(len1+1)] for _ in range(len2+1)]
        for i in range(len2):
            dp_table[i][-1] = len2 - i
        for j in range(len1):
            dp_table[-1][j] = len1 - j
        for i in range(len2-1, -1, -1):
            for j in range(len1-1, -1, -1):
                delta = 0 if word1[j] == word2[i] else 1
                dp_table[i][j] = min(1 + dp_table[i+1][j], 1 + dp_table[i][j+1], delta + dp_table[i+1][j+1])
        
        return dp_table[0][0]
    
  • 题型1:组合优化,被组合的东西必须连续

    • 前缀和 https://juejin.cn/post/6944913393627168798

      https://leetcode.cn/problems/maximum-difference-between-increasing-elements/

    • 和为K的子数组: https://leetcode-cn.com/problems/QTMn0o/

    • 区域和检索: https://leetcode-cn.com/problems/range-sum-query-2d-immutable/, https://leetcode-cn.com/problems/range-sum-query-immutable/

    • 连续子数组的最大和 https://leetcode.cn/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/

        题目描述:输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
                 要求时间复杂度为O(n)。
      
        示例1:
            输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
            输出: 6
            解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
      
      • 解答1:用 f ( i ) f(i) f(i) 代表以第 i i i 个数【结尾】的连续子数组的最大和,要求的答案就是:

        max ⁡ 0 ≤ i ≤ n − 1 { f ( i ) } \max_{0 \leq i \leq n-1} \{ f(i) \} 0in1max{f(i)}

        f ( i ) f(i) f(i),考虑是否将 n u m s [ i ] nums[i] nums[i]并入 f ( i − 1 ) f(i-1) f(i1)对应的那一段数组,得到递推式:

        f ( i ) = max ⁡ { n u m s [ i ] , f ( i − 1 ) + n u m s [ i ] } f(i)=\max\{nums[i], f(i-1) + nums[i]\} f(i)=max{nums[i],f(i1)+nums[i]}

      • 解答2:用 f ( i ) f(i) f(i) 代表以第 i i i 个数【开头】的连续子数组的最大和,要求的答案就是:

        max ⁡ 0 ≤ i ≤ n − 1 { f ( i ) } \max_{0 \leq i \leq n-1} \{ f(i) \} 0in1max{f(i)}

        f ( i ) f(i) f(i),考虑是否将 n u m s [ i ] nums[i] nums[i]并入 f ( i + 1 ) f(i+1) f(i+1)对应的那一段数组,得到递推式:

        f ( i ) = max ⁡ { n u m s [ i ] , f ( i + 1 ) + n u m s [ i ] } f(i)=\max\{nums[i], f(i+1) + nums[i]\} f(i)=max{nums[i],f(i+1)+nums[i]}

    • 连续子数组的最大积 https://leetcode.cn/problems/maximum-product-subarray/

  • 题型2:等式约束组合优化

    • 零钱兑换 https://leetcode.cn/problems/coin-change/

        题目描述:给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
      
                返回可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回-1。
      
                你可以认为每种硬币的数量是无限的。
      
        示例1:
            输入:coins = [1, 2, 5], amount = 11
            输出:3 
            解释:11 = 5 + 5 + 1
        示例2:
            输入:coins = [2], amount = 3
            输出:-1
        示例3:
            输入:coins = [1], amount = 0
            输出:0
      
      • 解答:该问题可建模为以下优化问题:

        min ⁡ ∑ i = 1 n x i     subject to ∑ i = 1 n x i ∗ c i = S \min \sum_{i=1}^{n} x_i\ \ \ \ \text{subject to} \sum_{i=1}^{n} x_i * c_i = S mini=1nxi    subject toi=1nxici=S

        其中, S S S 是总金额, c i c_i ci是第 i i i 枚硬币的面值, x i x_i xi i i i 枚硬币的数量。

        使用 f ( i ) f(i) f(i)表示组成金额 i i i所需最少的硬币数量,问题所求的是 f ( a m o u n t ) f(amount) f(amount)。假设 f ( i ) f(i) f(i)对应的方案组合已知,从中拿掉一个面值为 c c c的硬币,则剩下的硬币为 f ( i − c ) f(i-c) f(ic)对应的最优方案(否则的话, f ( i ) f(i) f(i)对应的不是最优方案,产生矛盾),因此 f ( i ) f(i) f(i)的递推式为:

        f ( i ) = min ⁡ j = 1 n f ( i − c j ) + 1 ,      1 ≤ i ≤ a m o u n t f(i) = \min_{j=1}^n f(i-c_j) + 1,\ \ \ \ 1\leq i \leq amount f(i)=j=1minnf(icj)+1,    1iamount

        注意到 i − c j i-c_j icj可能为0或者为负,因此要补充定义 f ( 0 ) = 0 f(0)=0 f(0)=0,如果 i = c j i=c_j i=cj,那么一个硬币就可以实现目标,原式子依然成立。完整的递推式为:

        f ( i ) = 0 ,      i = 0 f(i) = 0, \ \ \ \ i=0 f(i)=0,    i=0
        f ( i ) = min ⁡ j = 1 , c j ≤ i n f ( i − c j ) + 1 ,      1 ≤ i ≤ a m o u n t f(i) = \min_{j=1,c_j\leq i}^n f(i-c_j) + 1,\ \ \ \ 1\leq i \leq amount f(i)=j=1,cjiminnf(icj)+1,    1iamount

    • 单词拆分 https://leetcode.cn/problems/word-break/

  • 题型3:不等式约束组合优化,被组合的东西之间是并列关系,即背包问题及其变种

    • 01背包问题

        题目描述:有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
      
                第 i 件物品的体积是 v[i],价值是 w[i]。
      
                求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
      
      • 解答:01背包问题是一个不等式约束的组合优化问题,即

      max ⁡ ∑ i = 1 n w i x i     subject to ∑ i = 1 n v i ∗ x i ≤ V ,    x i = 0 , 1 \max \sum_{i=1}^{n} w_i x_i\ \ \ \ \text{subject to} \sum_{i=1}^{n} v_i * x_i \leq V,\ \ x_i=0,1 maxi=1nwixi    subject toi=1nvixiV,  xi=0,1

      使用 f ( i , j ) f(i,j) f(i,j)表示:只从前 i i i个物品中选,并且总体积不超过 j j j的选法,所能达到的最大价值。则问题所求的是 f ( N , V ) f(N,V) f(NV)

      对于第 i i i个物品,存在选与不选两个操作,如果选择,则前 i − 1 i-1 i1个物品的总体积不能超过 j − v [ i ] j-v[i] jv[i],因此,递推式为:

      f ( i , j ) = max ⁡ ( f ( i − 1 , j ) , f ( i − 1 , j − v [ i ] ) + w [ i ] ) f(i,j) = \max(f(i-1,j), f(i-1, j-v[i]) + w[i]) f(i,j)=max(f(i1,j),f(i1,jv[i])+w[i])

      边界情况: i − 1 i-1 i1可能为0,此时即没有任何物品,总价值自然就是0,所以安排 f ( 0 , : ) f(0,:) f(0,:)这一行都是0即可。此外, j − v [ i ] j-v[i] jv[i]也有可能为0或者为负,当为0时候,表示体积限制为0,总价值自然也是0,所以安排 f ( : , 0 ) f(:,0) f(:,0)这一列也都是0,此外,限制 j < v [ i ] j<v[i] j<v[i] 时候, f ( i , j ) = f ( i − 1 , j ) f(i,j)=f(i-1,j) f(i,j)=f(i1,j)。完整的递推式为:

      f ( i , j ) = 0 ,      i = 0   or   j = 0 f(i,j) = 0,\ \ \ \ i=0\ \ \text{or}\ \ j=0 f(i,j)=0,    i=0  or  j=0
      f ( i , j ) = f ( i − 1 , j )      1 ≤ i ≤ N , 1 ≤ j < v [ i ] f(i,j) = f(i-1,j)\ \ \ \ 1\leq i\leq N, 1\leq j < v[i] f(i,j)=f(i1,j)    1iN,1j<v[i]
      f ( i , j ) = max ⁡ ( f ( i − 1 , j ) , f ( i − 1 , j − v [ i ] ) + w [ i ] ) ,      1 ≤ i ≤ N , v [ i ] ≤ j ≤ V f(i,j) = \max(f(i-1,j), f(i-1, j-v[i]) + w[i]),\ \ \ \ 1\leq i\leq N, v[i]\leq j\leq V f(i,j)=max(f(i1,j),f(i1,jv[i])+w[i]),    1iN,v[i]jV

    • 完全背包问题

        题目描述:同上,但是不限制每件物品的使用次数。
      
      • 解答:递推式为:

      f ( i , j ) = 0 ,      i = 0   or   j = 0 f(i,j) = 0,\ \ \ \ i=0\ \ \text{or}\ \ j=0 f(i,j)=0,    i=0  or  j=0
      f ( i , j ) = max ⁡ k = 0 k ∗ v [ i ] ≤ j ( f ( i − 1 , j − k ∗ v [ i ] ) + k ∗ w [ i ] ) ,      1 ≤ i ≤ N , 1 ≤ j ≤ V f(i,j) = \max_{k=0}^{k*v[i] \leq j}(f(i-1, j-k*v[i]) + k*w[i]),\ \ \ \ 1\leq i\leq N, 1\leq j\leq V f(i,j)=k=0maxkv[i]j(f(i1,jkv[i])+kw[i]),    1iN,1jV

    • 选举

        题目描述:有 N 个州,第 i 个州的人口为 p[i],投票数为 v[i]。给定最小需要的票数为V
        
                求解最少需要的人口。
      
      • 解答:原问题为:

      min ⁡ ∑ i = 1 n p i x i     subject to ∑ i = 1 n v i ∗ x i ≥ V ,    x i = 0 , 1 \min \sum_{i=1}^{n} p_i x_i\ \ \ \ \text{subject to} \sum_{i=1}^{n} v_i * x_i \geq V,\ \ x_i=0,1 mini=1npixi    subject toi=1nvixiV,  xi=0,1

      转化为:

      max ⁡ ∑ i = 1 n − p i x i     subject to ∑ i = 1 n − v i ∗ x i ≤ − V ,    x i = 0 , 1 \max \sum_{i=1}^{n} -p_i x_i\ \ \ \ \text{subject to} \sum_{i=1}^{n} -v_i * x_i \leq -V,\ \ x_i=0,1 maxi=1npixi    subject toi=1nvixiV,  xi=0,1

      为了消去负值,使用全体求和,即

      max ⁡ ∑ i = 1 n − p i x i < − > ∑ i = 1 n p i + max ⁡ ∑ i = 1 n − p i x i = ∑ i = 1 n p i ( 1 − x i ) \max \sum_{i=1}^{n} -p_i x_i <-> \sum_{i=1}^{n} p_i +\max \sum_{i=1}^{n} -p_i x_i = \sum_{i=1}^{n} p_i (1 - x_i) maxi=1npixi<>i=1npi+maxi=1npixi=i=1npi(1xi)

      ∑ i = 1 n − v i ∗ x i ≤ − V < − > ∑ i = 1 n v i + ∑ i = 1 n − v i ∗ x i ≤ ∑ i = 1 n v i − V < − > ∑ i = 1 n v i ( 1 − x i ) ≤ ∑ i = 1 n v i − V \sum_{i=1}^{n} -v_i * x_i \leq -V <-> \sum_{i=1}^{n} v_i + \sum_{i=1}^{n} -v_i * x_i \leq \sum_{i=1}^{n} v_i - V <-> \sum_{i=1}^{n} v_i (1- x_i) \leq \sum_{i=1}^{n} v_i - V i=1nvixiV<>i=1nvi+i=1nvixii=1nviV<>i=1nvi(1xi)i=1nviV

      由于 x i = 0 , 1 x_i=0,1 xi=0,1 1 − x i 1-x_i 1xi也是0或者1,所以问题成为:

      max ⁡ ∑ i = 1 n p i x i     subject to ∑ i = 1 n v i ∗ x i ≤ ∑ i = 1 n v i − V ,    x i = 0 , 1 \max \sum_{i=1}^{n} p_i x_i\ \ \ \ \text{subject to} \sum_{i=1}^{n} v_i * x_i \leq \sum_{i=1}^{n} v_i-V,\ \ x_i=0,1 maxi=1npixi    subject toi=1nvixii=1nviV,  xi=0,1

      这是标准的01背包问题,只不过求解最后把选择的情况反选即可。

      边界情况:如果 ∑ i = 1 n v i < V \sum_{i=1}^{n} v_i<V i=1nvi<V,问题无解,因为凑了所有选票也达不到要求。

  • 题型4:不等式约束组合优化,组合的事物之间有马尔科夫性,即下一个选择的候选集取决于上一个选择

    • 跳跃游戏:https://leetcode.cn/problems/jump-game/

        题目描述:给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
                 数组中的每个元素代表你在该位置可以跳跃的最大长度。
                 判断你是否能够到达最后一个下标。
        
        示例1:
            输入:nums = [2,3,1,1,4]
            输出:true
            解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
      
        示例2:
            输入:nums = [3,2,1,0,4]
            输出:false
            解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。
      
      • 解答1:用 f ( i ) f(i) f(i) 表示从 i i i出发能不能到达最后一个下标 n n n,明显 f ( n ) = 1 f(n)=1 f(n)=1,而要求的答案为 f ( 0 ) f(0) f(0)

        i + 1 i+1 i+1 i + n u m s [ i ] i+nums[i] i+nums[i]中,只要有 f f f值为1,则 f ( i ) f(i) f(i)为1,递推式为:

        f ( i ) = f ( i + 1 )  or  f ( i + 2 )  or  . . .  or  f ( i + n u m s [ i ] ) f(i) = f(i+1)\ \text{or}\ f(i+2)\ \text{or}\ ...\ \text{or}\ f(i+nums[i]) f(i)=f(i+1) or f(i+2) or ... or f(i+nums[i])

        但是式子右边可能会出现超过 n n n的下标,为了规避这一点,修改为:

        f ( i ) = max ⁡ j = i + 1 min ⁡ { i + n u m s [ i ] , n } f j f(i) = \max_{j=i+1}^{\min\{i+nums[i], n\}} f_j f(i)=j=i+1maxmin{i+nums[i],n}fj

        复杂度 O ( n ∗ max ⁡ ( n u m s ) ) O(n*\max(nums)) O(nmax(nums))

        ''' V1
            执行用时:2948 ms, 在所有 Python 提交中击败了5.00%的用户
            通过测试用例:170 / 170
        '''
        def canJump(self, nums: List[int]) -> bool:
            result = [False] * len(nums)
            result[-1] = True
            for i in range(len(nums)-2, -1, -1):
                for j in range(i+1, min(len(nums), i+1+nums[i])):
                    if result[j]:
                        result[i] = True
                        break
        
            return result[0]
        
      • 解答2:贪心算法

        def canJump(self, nums: List[int]) -> bool:
            right_most = 0  # 记录最远能跳到哪
            for idx, val in enumerate(nums[:-1]): # 忽略最后一个位置
                right_most = max(right_most, idx+val)  # 当前位置上,最远能跳到哪
                # 如果最远都无法超过当前位置,那肯定无法到达最后一个位置,提前结束
                if right_most <= idx:
                    return False 
            return True
        
    • 打家劫舍 https://leetcode.cn/problems/house-robber/, https://leetcode.cn/problems/house-robber-ii/

    • 礼物的最大价值 https://leetcode.cn/problems/li-wu-de-zui-da-jie-zhi-lcof/

    • 最长“自定义”子序列

        题目描述:自定义可以是递增,递减或者相邻元素满足一定条件(如相差不超过5)
      
      • 解答:用 f ( i ) f(i) f(i) 表示从数组开头(以1 为第一个下标)到第i个位置的满足条件的最长子序列长度。

      f ( i ) = max ⁡ 1 ≤ j < i , ∣ n u m s [ j ] − n u m s [ i ] ∣ ≤ 5 f ( j ) + 1 f(i)=\max_{1\leq j < i, |nums[j]-nums[i]|\leq 5} f(j) + 1 f(i)=1j<i,nums[j]nums[i]5maxf(j)+1
      讨论两个边界情况:1. i = 1 i=1 i=1时候,显然 f ( i ) = 1 f(i)=1 f(i)=1; 2. 当 1 ≤ j < i 1\leq j <i 1j<i中没有条件满足 ∣ n u m s [ j ] − n u m s [ i ] ∣ ≤ 5 |nums[j]-nums[i]|\leq 5 nums[j]nums[i]5时候,显然f(i)=1。综合起来,初始化 f ( i ) = 1 , 1 ≤ i ≤ N f(i)=1,1\leq i\leq N f(i)=1,1iN即可。

  • 题型5:穷举所有可能的组合

    • 青蛙跳台阶问题 https://leetcode.cn/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/

      【这个例子可以很好地解释,动态规划可以从给定的数组左边开始计算,也可以从右边开始计算,具体取决于动态规划变量的定义。做题时候想到了如何分解子问题,就按照分解子问题的方式去做,不必拘泥于下标从哪里开始。】

        题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
      
            答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
      
        示例 1:
            输入:n = 2
            输出:2
        示例 2:
            输入:n = 7
            输出:21
        示例 3:
            输入:n = 0
            输出:1
      
      • 解答1:用 f ( i ) f(i) f(i) 表示【到达】第 i i i 级台阶的跳法种数,题目所求的结果为 f ( n ) f(n) f(n)

        要到达第 i i i 级台阶,可从第 i − 1 i-1 i1 级台阶或第 i − 2 i-2 i2 级台阶过来,所以递推式为:

        f ( i ) = f ( i − 1 ) + f ( i − 2 ) f(i)=f(i-1)+f(i-2) f(i)=f(i1)+f(i2)

        边界情况:由于 i − 1 , i − 2 i-1,i-2 i1,i2可能越界,因为当 n < 2 n<2 n<2的时候,直接返回结果1。完整的递推式为:

        f ( i ) = 1    i = 0 , 1 f(i)=1\ \ i=0,1 f(i)=1  i=0,1
        f ( i ) = f ( i − 1 ) + f ( i − 2 )    n ≥ i ≥ 2 f(i)=f(i-1)+f(i-2) \ \ n\geq i\geq 2 f(i)=f(i1)+f(i2)  ni2

        实际写代码的时候,不需要记住整个数组 f f f,只需要使用三个数字即可,代码如下:

        def numWays(self, n: int) -> int:
            if n <= 1:
                return 1
        
            a = 1
            b = 2
            for i in range(2, n):
                c = a + b
                a = b
                b = c
        
            return b % 1000000007
        
      • 解答2:用 f ( i ) f(i) f(i) 表示从第 i i i 级到第 n n n 级台阶的跳法种数,题目所求的结果为 f ( 0 ) f(0) f(0)

        递推式为:

        f ( i ) = f ( i + 1 ) + f ( i + 2 ) f(i)=f(i+1)+f(i+2) f(i)=f(i+1)+f(i+2)

        边界情况:由于 i + 1 , i + 2 i+1,i+2 i+1,i+2可能越界,因为当 n ≥ i > n − 2 n\geq i>n-2 ni>n2的时候,直接返回结果1。完整的递推式为:

        f ( i ) = 1    i = n − 1 , n f(i)=1\ \ i=n-1, n f(i)=1  i=n1,n
        f ( i ) = f ( i − 1 ) + f ( i − 2 )    0 ≤ i ≤ n − 2 f(i)=f(i-1)+f(i-2) \ \ 0\leq i \leq n-2 f(i)=f(i1)+f(i2)  0in2

        实际写代码的时候,只有微小不同:

        def numWays(self, n: int) -> int:
            if n <= 1:
                return 1
        
            a = 1
            b = 1
            for i in range(n-2, -1, -1):
                c = a + b
                a = b
                b = c
            return b % 1000000007
        
    • 不同的二叉搜索树 https://leetcode.cn/problems/unique-binary-search-trees/

        题目描述:给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
      
        示例 1:
            输入:n = 3
            输出:5
        示例 2:
            输入:n = 1
            输出:1
      
      • 解答:使用 f ( i ) f(i) f(i)表示 i i i个数字二叉搜索树的种数,问题所求的是 f ( n ) f(n) f(n)

        由于二叉搜索树的定义(左子树的最大者小于根,右子树的最小者大于根,并且左右子树要么只有一个节点,要么也是二叉搜索树),确定 i i i作为根节点之后,左子树只能由 i − 1 i-1 i1个数组成,

        【注意,这里不要拘泥于数字从1到i-1,因为从2到i也是一样的,重要的是有多少个数字】

        右子树只能由 n − i n-i ni个数组成,因此递推式为:

        f ( i ) = ∑ j = 1 i f ( j − 1 ) ∗ f ( i − j ) , 1 ≤ i ≤ n f(i) = \sum_{j=1}^{i} f(j-1) * f(i-j), 1\leq i \leq n f(i)=j=1if(j1)f(ij),1in

        边界情况:无

    • 不同路径 https://leetcode.cn/problems/unique-paths/

        题目描述:一个机器人位于一个 m x n 网格的左上角,机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角。
        
        问总共有多少条不同的路径?
      
      
        示例 1:
            输入:m = 3, n = 7
            输出:28
        示例 2:
            输入:m = 3, n = 2
            输出:3
            解释:
            从左上角开始,总共有 3 条路径可以到达右下角。
            1. 向右 -> 向下 -> 向下
            2. 向下 -> 向下 -> 向右
            3. 向下 -> 向右 -> 向下
        示例 3:
            输入:m = 7, n = 3
            输出:28
        示例 4:
            输入:m = 3, n = 3
            输出:6
      
      • 解答:使用 f ( i , j ) f(i,j) f(i,j)表示从 ( i , j ) (i,j) (i,j) ( m , n ) (m,n) (m,n)的不同路径数量,递推式为

        f ( i , j ) = f ( i + 1 , j ) + f ( i , j + 1 ) f(i,j) = f(i+1,j) + f(i,j+1) f(i,j)=f(i+1,j)+f(i,j+1)

        边界情况,由于 i + 1 , j + 1 i+1,j+1 i+1,j+1可能越界,因此对 f ( m , : ) , f ( : , n ) f(m,:),f(:,n) f(m,:)f(:,n)都设为1即可。完整递推式为:

        f ( i , j ) = 1 ,      i = m   or   j = n f(i,j) = 1, \ \ \ \ i=m\ \ \text{or}\ \ j=n f(i,j)=1,    i=m  or  j=n
        f ( i , j ) = f ( i + 1 , j ) + f ( i , j + 1 )      1 ≤ i < m , 1 ≤ j < n f(i,j) = f(i+1,j) + f(i,j+1)\ \ \ \ 1\leq i<m, 1\leq j <n f(i,j)=f(i+1,j)+f(i,j+1)    1i<m,1j<n

    • 数字翻译为字符串 https://leetcode.cn/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/

    • 分割回文 https://leetcode.cn/problems/palindrome-partitioning/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

张似衡

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

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

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

打赏作者

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

抵扣说明:

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

余额充值