代码随想录算法训练营第五十一天 | 115.不同的子序列 583.两个字符串的删除操作 72.编辑距离

115.不同的子序列

题目链接 文章讲解 视频讲解

动规五部曲:

  • dp[i][j]: 以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j],
  • 递推公式:
    • s[i-1]与t[j-1]相等
      • 需要是s[i-1]与t[j-1]匹配,那么个数为dp[i-1][j-1]即不需要考虑当前s子串和t子串的最后一位字母,所以只需要dp[i-1][j-1]
      • 不用s[i-1]来匹配,个数为dp[i-1][j]
    • s[i-1]与t[j-1]不相等: dp[i-1][j]
  • 初始化
    从递推公式dp[i-1][j-1] + dp[i-1][j];和dp[i][j] = dp[i-1][j]是从上方和左上方推导而来,所以dp[i][0]和dp[0][j]一定要初始化
    • dp[i][0]表示:以i-1为结尾的s可以随便删除元素,出现空字符串的分数,所以dp[i][0] = 1
    • dp[0][j]表示空字符串s可以随便删除元素,出现以j-1为结尾的字符串的个数,所以dp[0][j] = 0
  • 遍历顺序从上到下,从左向右
  • 打印dp数组
class Solution {
public:
    int numDistinct(string s, string t) {
        // dp[i][j]: 表示以i-1为结尾的s中有以j-1为结尾的t的个数
        vector<vector<uint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1, 0));

        // 递推公式 if(nums[i-1] == nums[j-1]) dp[i][j] = dp[i-1][j-1] + 1;

        // 初始化
        for(int i = 0; i <= s.size(); ++i) dp[i][0] = 1;
        for(int j = 1; j <= t.size(); ++j) dp[0][j] = 0;

        for(int i = 1; i <= s.size(); ++i) {
            for(int j = 1; j <= t.size(); ++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];
            }
        }

        // for(auto vec : dp) {
        //     for(int val : vec) cout << val << " ";
        //     cout << endl;
        // }

        return dp[s.size()][t.size()];
    }
};

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

题目链接 文章讲解 视频讲解

class Solution {
public:
    int minDistance(string word1, string word2) {
        // dp[i][j]: 使得word1的i-1和word2的j-1相等所需的最少操作
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));

        // 递推公式:if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
        // else dp[i][j] = dp[i-1][j-1] + 2;
        
        // 初始化
        for(int i = 0; i <= word1.size(); ++i) dp[i][0] = i;
        for(int j = 0; j <= word2.size(); ++j) dp[0][j] = j;


        for(int i = 1; i <= word1.size(); ++i) {
            for(int j = 1; j <= word2.size(); ++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[i][j]: 表示word1的i-1位置和word2[j-1]位置相同所需的最小操作次数

  • 递推公式

    • word1[i-1] == word2[j-1]: dp[i][j] = dp[i-1][j-1]
    • word1[i-1] != word2[j-1]
      • 考虑word1的i-1位置(将word1的i位置删除):dp[i][j] = dp[i-1][j] + 1;
      • 考虑word2的j-1位置(将word2的j位置删除): dp[i][j] = dp[i][j-1] + 1;
      • 两个位置的元素都考虑(替换一个元素): dp[i][j] = dp[i-1][j-1] + 1;
  • 初始化

    • word2为空时,需要将word1调整为和word2相同,需要逐个删除word1中的元素,所以dp[i][0] = i;(有几个元素就执行几次删除操作)
    • 同理dp[0][j] = j;
  • 遍历顺序:从上到下,从左到右

  • 打印dp数组

class Solution {
public:
    int minDistance(string word1, string word2) {
        // dp[i][j]: 表示word1的i-1位置和word2[j-1]位置相同所需的最小操作次数
        vector<vector<int>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));

        // 递推公式:

        // 初始化
        for(int i = 0; i <= word1.size(); ++i) dp[i][0] = i;
        for(int j = 0; j <= word2.size(); ++j) dp[0][j] = j;

        // 遍历
        for(int i = 1; i <= word1.size(); ++i) {
            for(int j = 1; j <= word2.size(); ++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, min(dp[i][j-1] + 1, dp[i-1][j-1] + 1));
            }
        }

        for(auto vec : dp) {
            for(int val : vec) cout << val << " ";
            cout << endl;
        }

        return dp[word1.size()][word2.size()];
    }
posted @ 2024-07-05 16:15  深蓝von  阅读(1)  评论(0编辑  收藏  举报