7.2 多维动态规划

        多维动态规划是动态规划的一个扩展,它处理的问题通常具有多个维度的状态空间。在标准的一维动态规划中,状态通常依赖于一个变量,比如时间步或者位置。然而,在多维动态规划中,状态可能依赖于两个或更多的变量,这增加了问题的复杂性和求解难度。

在多维动态规划中,关键步骤包括:

1. **状态定义**:
   - 定义状态空间,也就是决定你的问题中的哪些变量是重要的。
   - 每个状态通常表示为一个元组,例如 `(i, j, k)`,其中 `i`, `j`, `k` 是影响问题解决方案的不同维度的值。

2. **状态转移方程**:
   - 确定如何从一个状态转移到另一个状态。
   - 这通常涉及到一个递推关系,比如 `dp[i][j][k] = min(dp[i-1][j][k], dp[i][j-1][k], dp[i][j][k-1]) + cost(i, j, k)`。

3. **初始化**:
   - 确定边界条件,即状态空间的起点。
   - 这些通常是已知的或者可以通过简单计算得到的初始状态。

4. **计算顺序**:
   - 决定状态的计算顺序,通常是从低维状态向高维状态计算。
   - 这是为了确保在计算一个状态之前,所有依赖它的状态都已经计算完成。

5. **记忆化或表格法**:
   - 使用一个多维数组来存储已经计算过的结果,避免重复计算。
   - 这是动态规划的关键,可以大大减少计算量。

6. **最终答案**:
   - 最终答案通常是状态空间中某个特定状态的值。

多维动态规划常用于各种复杂问题,如库存管理、投资组合优化、路径寻找问题等。例如,在解决三维背包问题时,状态可能包含物品的数量、重量和体积三个维度。

理解多维动态规划的关键在于能够清晰地定义状态空间和状态转移规则。一旦这些被正确建立,问题就可以通过迭代填充多维数组的方式得到解决。由于状态空间的增加,多维动态规划问题可能会遇到“维数灾难”,即状态数量随维度指数级增长,因此选择合适的数据结构和算法优化变得尤为重要。

62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

我觉得做题目,要么从前往后推理,要么从后往前推理论。

你看这个题目,试想一下,我们达达某一个位置,那么到当前位置直接关联的上一步是什么呢?

要么从上面过来的,要么从左面过来的:

所以就有:

dp[i][j]: 到第i行第j列的路径总数;

dp[i][j] = dp[i-1][j] + dp[i][j-1];

边界条件:

就是两边dp[i][0] = 1, dp[0][i] = 1

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        sum = 0
        dp = [[0]*n for _ in range(m)]
        #dp[0][0] = 1

        for row in range(m):
            for col in range(n):
                if row==0 and col==0:
                    dp[row][col] = 1
                    continue

                if row==0:
                    dp[row][col] = dp[row][col-1]
                    continue

                if col == 0:
                    dp[row][col] = dp[row-1][col]
                    continue
                
                dp[row][col] += dp[row-1][col]+dp[row][col-1]
        return dp[m-1][n-1]

5. 最长回文子串

给你一个字符串 s,找到 s 中最长的 回文子串。

思考:

怎么才能算回文:s = s[::-1]

长度大于2的,用 P(i,j) 表示字符串 s 的第 i 到 j 个字母组成的串(下文表示成 s[i:j])是否为回文串:

这里的「其它情况」包含两种可能性:

  • s[i,j] 本身不是一个回文串;

  • i>j,此时 s[i,j] 本身不合法。

那么我们就可以写出动态规划的状态转移方程:

P(i,j)=P(i+1,j−1)∧(Si​==Sj​)

特别的长度等于2的:

注意:在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。

class Solution:
    def longestPalindrome(self, s: str) -> str:
        length = len(s)
        if length<=0:
            return s
        
        dp = [[False] * length for _ in range(length)]
        for i in range(length):
            dp[i][i] = True
        
        max_len = 1
        result = s[0]
        # 序列可能长度的遍历
        for L in range(2, length+1):
            for i in range(length):
                j = i+L-1
                # 出界了
                if j>=length:
                    break
                
                if s[i]!=s[j]:
                    dp[i][j] = False
                else:
                    # 长度小于3的
                    if L<=3:
                        dp[i][j]=True
                    else:
                        dp[i][j] = dp[i+1][j-1]
            
                if dp[i][j] and max_len< L:
                    max_len = L
                    result = s[i:j+1]
        return result

1143. 最长公共子序列

给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入:text1 = "abcde", text2 = "ace" 
输出:3  
解释:最长公共子序列是 "ace" ,它的长度为 3 。

示例 2:

输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc" ,它的长度为 3 。

比如对于本题而言,可以定义 dp[i][j] 表示 text1[0:i-1] 和 text2[0:j-1] 的最长公共子序列。 (注:text1[0:i-1] 表示的是 text1 的 第 0 个元素到第 i - 1 个元素,两端都包含)
之所以 dp[i][j] 的定义不是 text1[0:i] 和 text2[0:j] ,是为了方便当 i = 0 或者 j = 0 的时候,dp[i][j]表示的为空字符串和另外一个字符串的匹配,这样 dp[i][j] 可以初始化为 0.

  1. 当 text1[i - 1] == text2[j - 1] 时,说明两个子字符串的最后一位相等,所以最长公共子序列又增加了 1,所以 dp[i][j] = dp[i - 1][j - 1] + 1;举个例子,比如对于 ac 和 bc 而言,他们的最长公共子序列的长度等于 a 和 b 的最长公共子序列长度 0 + 1 = 1。
  2. 当 text1[i - 1] != text2[j - 1] 时,说明两个子字符串的最后一位不相等,那么此时的状态 dp[i][j] 应该是 dp[i - 1][j] 和 dp[i][j - 1] 的最大值。举个例子,比如对于 ace 和 bc 而言,他们的最长公共子序列的长度等于 ① ace 和 b 的最长公共子序列长度0 与 ② ac 和 bc 的最长公共子序列长度1 的最大值,即 1。

总结: 

如果当前连个对比的字符串相等:i,j, 肯定是之前的字序列最大长度 + 1

s1[i] ==  s2[j] : dp[i][j] = dp[i-1][j-1] + 1

如果不相同,也取之前子问题序列最大值: 

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

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        leg1 = len(text1)
        leg2 = len(text2)
        # dp[i][j]: 序列s1[:i+1], s2[:j+1],最长公共子序列
        max_len = 0
        dp = [[0]*(leg2+1) for _ in range(leg1+1)]
        
        for i in range(1,leg1+1):
            for j in range(1,leg2+1):
                if text1[i-1]!=text2[j-1]:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
                else:
                    dp[i][j] = dp[i-1][j-1] + 1
        return dp[leg1][leg2]
            

相关推荐

  1. 动态规划】Leetcode 72. 编辑距离【中等】

    2024-07-18 14:08:02       25 阅读
  2. 【Leetcode】top 100 动态规划

    2024-07-18 14:08:02       38 阅读
  3. 【LeetCode热题100】【动态规划】编辑距离

    2024-07-18 14:08:02       26 阅读
  4. 力扣 hot100 -- 动态规划

    2024-07-18 14:08:02       19 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-18 14:08:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-18 14:08:02       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-18 14:08:02       58 阅读
  4. Python语言-面向对象

    2024-07-18 14:08:02       69 阅读

热门阅读

  1. 算法面试题六

    2024-07-18 14:08:02       22 阅读
  2. c++数据结构——栈

    2024-07-18 14:08:02       20 阅读
  3. 搞定前端面试题——TCP和UDP!!!

    2024-07-18 14:08:02       20 阅读
  4. vue2路由跳转是异步的

    2024-07-18 14:08:02       21 阅读
  5. 日有所增,不见其长

    2024-07-18 14:08:02       20 阅读
  6. Python面试整理-Python的数据类型,分别有哪些?

    2024-07-18 14:08:02       20 阅读
  7. WordPress与 wp-cron.php

    2024-07-18 14:08:02       15 阅读
  8. LeetCode //C - 231. Power of Two

    2024-07-18 14:08:02       21 阅读
  9. Leetcode617. 两个二叉树相加

    2024-07-18 14:08:02       16 阅读
  10. request method ‘DELETE‘ is not supported问题

    2024-07-18 14:08:02       21 阅读
  11. 【日常技能】excel 换行符替换的3个方法完美解决

    2024-07-18 14:08:02       21 阅读
  12. C# —— Sort排序

    2024-07-18 14:08:02       24 阅读