LeetCode-22day:多维动态规划

多维动态规划经典题目总结(C++实现)

多维动态规划是动态规划的一种扩展,适用于更复杂的问题。本文总结了五道经典的多维动态规划问题,帮助你更好地理解和掌握多维动态规划的应用。


🟢 1. 不同路径(Unique Paths)

📄 题目描述:

一个机器人位于一个 m x n 网格的左上角,只能向下或向右移动。它试图到达网格的右下角。有多少种不同的路径可以到达?

🧠 解题思路(简洁版)

  • 动态规划
    • f[j] 表示到达第 j 列的路径数。
    • 状态转移:f[j] = f[j] + f[j - 1]
    • 初始化:第一行全为 1。

⏱️ 复杂度分析

  • 时间复杂度:O(m × n),其中 mn 分别为行数和列数。
  • 空间复杂度:O(n),优化后的动态规划表。

✅ C++ 实现

cpp 复制代码
class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int> f(n, 1);
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                f[j] += f[j - 1];
            }
        }
        return f[n - 1];
    }
};

🟢 2. 最小路径和(Minimum Path Sum)

📄 题目描述:

给定一个 m x n 的网格 grid,每个单元格包含一个非负整数,表示该单元格的代价。从左上角到右下角的路径,路径上的代价总和最小是多少?

🧠 解题思路(简洁版)

  • 动态规划
    • dp[i][j] 表示到达 (i, j) 的最小路径和。
    • 初始化第一行和第一列。
    • 状态转移:dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]

⏱️ 复杂度分析

  • 时间复杂度:O(m × n),其中 mn 分别为行数和列数。
  • 空间复杂度:O(m × n),动态规划表。

✅ C++ 实现

cpp 复制代码
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if (grid.size() == 0 || grid[0].size() == 0) return 0;

        int rows = grid.size(), columns = grid[0].size();
        vector<vector<int>> dp(rows, vector<int>(columns));

        dp[0][0] = grid[0][0];
        for (int i = 1; i < rows; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }
        for (int j = 1; j < columns; j++) {
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }
        for (int i = 1; i < rows; i++) {
            for (int j = 1; j < columns; j++) {
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[rows - 1][columns - 1];
    }
};

🟢 3. 最长回文子串(Longest Palindromic Substring)

📄 题目描述:

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

🧠 解题思路(简洁版)

  • 动态规划
    • dp[i][j] 表示子串 ( s[i:j] ) 是否为回文。
    • 初始化:单个字符是回文。
    • 状态转移:若 ( s[i] = s[j] ) 且 ( j - i < 3 ) 或 ( dp[i+1][j-1] ) 为真,则 ( dp[i][j] ) 为真。
    • 遍历所有可能的子串长度,更新最长回文子串的起始位置和长度。

⏱️ 复杂度分析

  • 时间复杂度:O(n²),其中 n 为字符串长度。
  • 空间复杂度:O(n²),动态规划表。

✅ C++ 实现

cpp 复制代码
class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n < 2) return s;

        int maxLen = 1;
        int begin = 0;
        vector<vector<int>> dp(n, vector<int>(n));
        for (int i = 0; i < n; i++) dp[i][i] = true;

        for (int L = 2; L <= n; L++) {
            for (int i = 0; i < n; i++) {
                int j = L + i - 1;
                if (j >= n) break;
                if (s[i] != s[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) dp[i][j] = true;
                    else dp[i][j] = dp[i + 1][j - 1];
                }
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substr(begin, maxLen);
    }
};

🟢 4. 最长公共子序列(Longest Common Subsequence)

📄 题目描述:

给定两个字符串 text1text2,找到它们的最长公共子序列的长度。

🧠 解题思路(简洁版)

  • 动态规划
    • dp[i][j] 表示 text1i 个字符和 text2j 个字符的最长公共子序列长度。
    • 状态转移:
      • text1[i-1] == text2[j-1],则 dp[i][j] = dp[i-1][j-1] + 1
      • 否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    • 初始化:dp[i][0] = dp[0][j] = 0

⏱️ 复杂度分析

  • 时间复杂度:O(m × n),其中 mn 分别为两个字符串的长度。
  • 空间复杂度:O(m × n),动态规划表。

✅ C++ 实现

cpp 复制代码
class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m = text1.length(), n = text2.length();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        for (int i = 1; i <= m; i++) {
            char c1 = text1.at(i - 1);
            for (int j = 1; j <= n; j++) {
                char c2 = text2.at(j - 1);
                if (c1 == c2) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp[m][n];
    }
};

🟢 5. 编辑距离(Edit Distance)

📄 题目描述:

给定两个字符串 word1word2,计算将 word1 转换为 word2 所需的最少操作次数。操作包括插入、删除和替换字符。

🧠 解题思路(简洁版)

  • 动态规划
    • dp[i][j] 表示 word1i 个字符和 word2j 个字符的最小编辑距离。
    • 状态转移:
      • 插入:dp[i][j-1] + 1
      • 删除:dp[i-1][j] + 1
      • 替换:dp[i-1][j-1] + (word1[i-1] != word2[j-1])
    • 初始化:dp[i][0] = idp[0][j] = j

⏱️ 复杂度分析

  • 时间复杂度:O(m × n),其中 mn 分别为两个字符串的长度。
  • 空间复杂度:O(m × n),动态规划表。

✅ C++ 实现

cpp 复制代码
class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.length();
        int m = word2.length();

        if (n * m == 0) return n + m;
        vector<vector<int>> dp(n + 1, vector<int>(m + 1));

        for (int i = 0; i < n + 1; i++) dp[i][0] = i;
        for (int j = 0; j < m + 1; j++) dp[0][j] = j;

        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < m + 1; j++) {
                int left = dp[i - 1][j] + 1;
                int down = dp[i][j - 1] + 1;
                int left_down = dp[i - 1][j - 1];
                if (word1[i - 1] != word2[j - 1]) left_down += 1;
                dp[i][j] = min(left, min(down, left_down));
            }
        }
        return dp[n][m];
    }
};

📌 总结

题目 方法 时间复杂度 空间复杂度
不同路径 动态规划 O(m × n) O(n)
最小路径和 动态规划 O(m × n) O(m × n)
最长回文子串 动态规划 O(n²) O(n²)
最长公共子序列 动态规划 O(m × n) O(m × n)
编辑距离 动态规划 O(m × n) O(m × n)

希望本文对你有所帮助!如果你还有其他问题,欢迎继续提问。

相关推荐
艾莉丝努力练剑1 小时前
【C语言16天强化训练】从基础入门到进阶:Day 11
c语言·学习·算法
岁月静好20253 小时前
Leetcode 深度优先搜索 (15)
算法·leetcode·深度优先
离越词4 小时前
C++day1作业
数据结构·c++·算法
凤年徐4 小时前
【数据结构与算法】LeetCode 20.有效的括号
c语言·数据结构·算法·leetcode
医工交叉实验工坊5 小时前
R 语言 ComplexUpset 包实战:替代 Venn 图的高级集合可视化方案
算法·r语言
东皇太星6 小时前
模运算(密码学/数论/算法)
数据结构·算法·密码学
一水鉴天7 小时前
整体设计 修订 之1 三“先”之“基” 与范畴重构:康德先验哲学的批判性程序化实现
java·人工智能·算法
剪一朵云爱着7 小时前
PAT 1086 Tree Traversals Again
算法·pat考试
JuneXcy8 小时前
流程控制语句(3)
c语言·算法