• 53. 最大子序和 392.判断子序列 115.不同的子序列 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇


    53. 最大子序和 

    题目:

    给定一个整数数组,求最大连续子序列和。(至少包含一个元素)

    示例:

    • 输入: [-2,1,-3,4,-1,2,1,-5,4]
    • 输出: 6
    • 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6
    • 意为为了连续最大负数都可以包含进来。

    dp数组含义:

    dp[i]:包括下标i(以nums[i]为结尾)的最大连续子序列和为dp[i]

    1. class Solution {
    2. public:
    3. int maxSubArray(vector<int>& nums) {
    4. if (nums.size() == 0) return 0;
    5. vector<int> dp(nums.size());
    6. dp[0] = nums[0];
    7. int result = dp[0];
    8. for (int i = 1; i < nums.size(); i++) {
    9. dp[i] = max(dp[i - 1] + nums[i], nums[i]); // 状态转移公式
    10. if (dp[i] > result) result = dp[i]; // result 保存dp[i]的最大值
    11. }
    12. return result;
    13. }
    14. };

     用递推公式 dp[i] = max(dp[i - 1] + nums[i], nums[i])推导可以看出,若上一步的dp值加上当前遍历的nums值 大于 当前遍历的nums值,则取dp[i - 1] + nums[i],否则取nums[i]。

    这样可以保证连续的值一直是最大值,不符和就从当前的nums值重新开始。

      392.判断子序列

    题目:

    给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

    字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

    dp数组含义:

    dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]

    1. class Solution {
    2. public:
    3. bool isSubsequence(string s, string t) {
    4. vectorint>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));
    5. for (int i = 1; i <= s.size(); i++) {
    6. for (int j = 1; j <= t.size(); j++) {
    7. if (s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
    8. else dp[i][j] = dp[i][j - 1];
    9. }
    10. }
    11. if (dp[s.size()][t.size()] == s.size()) return true;
    12. return false;
    13. }
    14. };

    115.不同的子序列 

    题目:

    给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。

    dp数组含义:

    dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

    1. class Solution {
    2. public:
    3. int numDistinct(string s, string t) {
    4. vectoruint64_t>> dp(s.size() + 1, vector<uint64_t>(t.size() + 1));
    5. for (int i = 0; i < s.size(); i++) dp[i][0] = 1;
    6. for (int j = 1; j < t.size(); j++) dp[0][j] = 0;
    7. for (int i = 1; i <= s.size(); i++) {
    8. for (int j = 1; j <= t.size(); j++) {
    9. if (s[i - 1] == t[j - 1]) {
    10. dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
    11. } else {
    12. dp[i][j] = dp[i - 1][j];
    13. }
    14. }
    15. }
    16. return dp[s.size()][t.size()];
    17. }
    18. };

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

    题目:

    给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。

    • 输入: "sea", "eat"
    • 输出: 2
    • 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea

    dp数组含义:

    dp[i][j]:以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。

    1. class Solution {
    2. public:
    3. int minDistance(string word1, string word2) {
    4. vectorint>> dp(word1.size() + 1, vector<int>(word2.size() + 1));
    5. for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
    6. for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
    7. for (int i = 1; i <= word1.size(); i++) {
    8. for (int j = 1; j <= word2.size(); j++) {
    9. if (word1[i - 1] == word2[j - 1]) {
    10. dp[i][j] = dp[i - 1][j - 1];
    11. } else {
    12. dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1})
    13. }
    14. }
    15. }
    16. return dp[word1.size()][word2.size()];
    17. }
    18. };

    看见了最左上角的右边和下边从0开始赋值的初始化1...n

    字符匹配dp[i][j] = dp[i - 1][j - 1];字符不匹配  dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

    最后结果依照dp数组定义,返回最右下角值

    递推公式;

    • 当word1[i - 1] 与 word2[j - 1]相同的时候
    • 当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],最少操作次数为dp[i - 1][j] + 1

    情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1

    情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2

    取最小值递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

    初始化:

    从递推公式 dp[i][j] = min(dp[i - 1][j - 1] + 2, min(dp[i - 1][j], dp[i][j - 1]) + 1); 和dp[i][j] = dp[i - 1][j - 1]可以看出dp[i][j]都是根据左上方、正上方、正左方推出来的。(同时遍历顺序也要求左到右,上到下,包装存在这些值)

    所以dp[i][0] 和 dp[0][j]一定要初始化的。

    一边单词为0的字符串,另一边要怎么删才相等呢,当然是有多少删多少,一个为i,一个为j

    1. vectorint>> dp(word1.size() + 1, vector<int>(word2.size() + 1));
    2. for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
    3. for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;

     72. 编辑距离 

    题目:

    给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。

    你可以对一个单词进行如下三种操作:

    • 插入一个字符

    • 删除一个字符

    • 替换一个字符

    • 示例 2:

    • 输入:word1 = "intention", word2 = "execution"

    • 输出:5

    • 解释: intention -> inention (删除 't') inention -> enention (将 'i' 替换为 'e') enention -> exention (将 'n' 替换为 'x') exention -> exection (将 'n' 替换为 'c') exection -> execution (插入 'u')

    dp数组含义:

    dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。

     

    递推公式:

    dp[i][j]由4种情况推出,

    1. if (word1[i - 1] == word2[j - 1])
    2. 不操作
    3. if (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]时

    • 删除:dp[i][j] = dp[i - 1][j] + 1;

    操作数+1,忽略当前值,继续遍历寻找匹配值

    • 增加:dp[i][j] = dp[i][j - 1] + 1;

    这里的删除相当于增加,word2添加一个元素,相当于word1删除一个元素

    例如 word1 = "ad" ,word2 = "a"word1删除元素'd' 和 word2添加一个元素'd'的操作数都是1,由于求的也是操作数,所以,增加word1一次相当于删除word2一次

    所以增加公式:dp[i][j] = dp[i][j - 1] + 1;

    • 换改:dp[i][j] = dp[i - 1][j - 1];

    换改后,word1[i - 1] 和word2[j - 1]从不相等变成了相等,所以用 dp[i][j] = dp[i - 1][j - 1];

    综合后递归公式代码如下:

    1. if (word1[i - 1] == word2[j - 1]) {
    2. dp[i][j] = dp[i - 1][j - 1];
    3. }
    4. else {
    5. dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
    6. }

    初始化: 

    dp[i][j]的定义:

    dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]

    dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。

    那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i;

    同理dp[0][j] = j;

    1. for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
    2. for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;

     遍历顺序:

    由图可看出,递推公式依赖关系。即从左到右从上到下去遍历。

    总代码:

    1. class Solution {
    2. public:
    3. int minDistance(string word1, string word2) {
    4. vectorint>> dp(word1.size() + 1, vector<int>(word2.size() + 1, 0));
    5. for (int i = 0; i <= word1.size(); i++) dp[i][0] = i;
    6. for (int j = 0; j <= word2.size(); j++) dp[0][j] = j;
    7. for (int i = 1; i <= word1.size(); i++) {
    8. for (int j = 1; j <= word2.size(); j++) {
    9. if (word1[i - 1] == word2[j - 1]) {
    10. dp[i][j] = dp[i - 1][j - 1];
    11. }
    12. else {
    13. dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
    14. }
    15. }
    16. }
    17. return dp[word1.size()][word2.size()];
    18. }
    19. };

    115和583被吞了。

  • 相关阅读:
    万界星空科技/生产制造执行MES系统/开源MES/免费MES
    Kafka ProducerRecord如何写入到RecordAccumulator
    C. Ntarsis‘ Set
    LVGL中LV_SCROLL_SNAP_CENTER宏的作用
    程序员面试中的测试驱动开发:如何展示你的编程范式
    猴子选大王[加强版]
    适合开发者使用的6款浏览器,开发者工具很实用
    tessafe.sys是病毒吗?tessafe.sys不兼容驱动程序如何解决?
    分享从零开始学习网络设备配置--任务3.7 使用动态路由RIPv2实现网络连通
    stableDiffusion安装
  • 原文地址:https://blog.csdn.net/qq_70280303/article/details/134321296