动态规划Day33:编辑距离

392. 判断子序列

与最长公共子序列(LCS)的区别是,不能放弃s中的任何字符,所以当出现字符不匹配时,只能放弃t中的字符。

cpp 复制代码
    bool isSubsequence(string s, string t) {
        vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));
        for(int i = 1 ; i < s.size() + 1; i++){
            for(int j = 1; j < t.size() + 1; j++){
                if(s[i - 1] == t[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = dp[i][j - 1];
                }
            }
        }
        if(dp[s.size()][t.size()] == s.size()){
            return true;
        }
        return false;
    }

115. 不同的子序列

dpij表示 字符串 s 的前 i 个字符(s[0..i-1])中,包含字符串 t 的前 j 个字符(t[0..j-1])的子序列个数。

初始化

dp[i][0] = 1(对任意 i):t 的前 0 个字符(空字符串),是任何 s 的前 i 个字符的子序列(空序列只有 1 种选法:什么都不选);

dp[0][j] = 0(j>0):s 的前 0 个字符(空字符串),无法包含非空的 t 的前 j 个字符,个数为 0。

递推公式,si - 1 == tj - 1时,需要

递推公式

匹配:dp[i][j] = 用当前字符(dp[i-1][j-1]) + 不用当前字符(dp[i-1][j]);

不匹配:dp[i][j] = 不用当前字符(dp[i-1][j]);

cpp 复制代码
int numDistinct(string s, string t) {
        vector<vector<unsigned long long>> dp(s.size()+1, vector<unsigned long long>(t.size()+1));
        for(int i = 0; i < s.size()+1; i++){
            dp[i][0] = 1;
        }
        for(int j = 1; j < t.size()+1; j++){
            dp[0][j] = 0;
        }
        for(int i = 1; i < s.size()+1; i++){
            for(int j = 1; j < t.size()+1; j++){
                if(s[i - 1] == t[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                } else{
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[s.size()][t.size()];
    }

583. 两个字符串的删除操作

可以转换成 寻找最大公共子序列,最后用两个字符串的长度分别减去最长公共子序列的长度,再相加就是答案

cpp 复制代码
int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
        int res = 0;
        for(int i = 1; i < word1.size() + 1; i++){
            for(int j = 1; j < word2.size() + 1; j++){
                if(word1[i - 1] == word2[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
                res = max(res, dp[i][j]);
            }
        }
        return word1.size() + word2.size() - res * 2;
    }

方法二

DP 定义:dp[i][j] 表示将 word1 前 i 个字符转换为 word2 前 j 个字符所需的最少操作数(仅含删除、插入)。

初始化:

  • dp[i][0] = i:word2 为空时,需删除 word1 前 i 个字符(共 i 次操作);

  • dp[0][j] = j:word1 为空时,需插入 word2 前 j 个字符(共 j 次操作)。

状态转移:

  • 字符匹配(word1[i-1] == word2[j-1]):无需操作,继承 dp[i-1][j-1];

  • 字符不匹配:取「删除 word1 当前字符(dp[i-1][j]+1)」或「插入 word2 当前字符(dp[i][j-1]+1)」的最小值。

cpp 复制代码
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1));
        for(int i = 0; i < word1.size() + 1; i++){
            dp[i][0] = i;
        }
        for(int j = 1; j < word2.size() + 1; j++){
            dp[0][j] = j;
        }
        for(int i = 1; i < word1.size() + 1; i++){
            for(int j = 1; j < word2.size() + 1; j++){
                if(word1[i - 1] == word2[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }

72. 编辑距离

DP 定义 :dp[i][j] 表示将 word1 前 i 个字符转换为 word2 前 j 个字符所需的最少操作数(支持插入、删除、替换三种操作)。

初始化:

  • dp[i][0] = i:word2 为空时,删除 word1 前 i 个字符(共 i 次操作);

  • dp[0][j] = j:word1 为空时,插入 word2 前 j 个字符(共 j 次操作)。

状态转移:

  • 字符匹配:无需操作,直接继承 dp[i-1][j-1];

  • 字符不匹配:取「删除(dp[i-1][j]+1)、删除(dp[i][j-1]+1)、替换(dp[i-1][j-1]+1)」三者最小值。

删除word1 ,就是增加word2,所以对两个都执行山删除操作可以视为其中一次删除是对另一个的增加

结果 :dp[word1.size()][word2.size()] 即为转换的最少操作数。

cpp 复制代码
    int minDistance(string word1, string word2) {
        vector<vector<int>> dp(word1.size() + 1, vector<int> (word2.size() + 1));
        for(int i = 0; i < word1.size() + 1; i++){
            dp[i][0] = i;
        }
        for(int j = 1; j < word2.size() + 1; j++){
            dp[0][j] = j;
        }
        for(int i = 1; i < word1.size() + 1;i++){
            for(int j = 1; j < word2.size() + 1; j++){
                if(word1[i - 1] == word2[j - 1]){
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = min( min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 1);
                }
            }
        }
        return dp[word1.size()][word2.size()];
    }
相关推荐
niyongsheng1 分钟前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
j7~3 小时前
【穷举、深搜与回溯算法】一棵决策树讲透全排列与子集
数据结构·c++·算法·leetcode·回溯·递归
傅科摆 _ py3 小时前
DP,贪心,堆和栈,二分力扣复习
开发语言·python·算法
Shaoshing4 小时前
LeetCode100 42.接雨水
java·算法·leetcode
域限奇点访客4 小时前
用AI生成问卷的网站怎么选?看题目录入结构、题型映射和生成后的校验
算法
not coder5 小时前
一文讲通--从树到红黑树
数据结构·算法
octopus_c5 小时前
C++ 入门
开发语言·c++·算法
ZhengEnCi6 小时前
2026年10月30日AI早报:Gemini 4 Carbon登顶、DeepSeek融资1055亿、智元机器人上岗实测
人工智能·算法
强哥聊算力6 小时前
《算力江湖·Intel帝国往事》第三集:安迪·格鲁夫的铁血时代:Intel为什么能把对手逼到墙角?
运维·人工智能·科技·算法·ai·gpu算力
Shaoshing6 小时前
LeetCode100 11. 盛最多水的容器
算法·leetcode