首页 > 编程语言 >代码随想录算法训练营day45| 115.不同的子序列 583. 两个字符串的删除操作 72. 编辑距离

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

时间:2024-11-13 22:23:02浏览次数:1  
标签:583 删除 随想录 len 115 range word1 word2 dp

学习资料:https://programmercarl.com/0115.不同的子序列.html#算法公开课

动态规划系列之编辑距离问题

学习记录:
115.不同的子序列(当遇到相同字母时,可以选择也可以不选;刚开始没看懂;dp[i][j]是对应i-1结尾和j-1结尾,这样的目的是方便第一行和第一列初始化)

点击查看代码
class Solution(object):
    def numDistinct(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: int
        """
        # 动态规划解法
        # dp[i][j]表示以j-1为结尾的t片段和以i-1为结尾的s片段,前者作为后者的子序列的情况数量
        dp = [[0]*(len(t)+1) for _ in range(len(s)+1)]
        # 初始化 dp[i][0], dp[0][j], dp[0][0]
        for i in range(len(s)):
            dp[i][0] = 1     # j-1=-1,那此时t片段是空字符串,这个就是t片段的子序列
                             # 特别的,这里设定了,dp[0][0] = 1,下面要避开
        for j in range(1, len(t)+1):
            dp[0][j] = 0      # i-1 =-1,那此时t片段不为空,而s片段是空字符串,那肯定不是后者的子序列
        
        # 开始遍历
        for i in range(1, len(s)+1):
            for j in range(1, len(t)+1):
                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[-1][-1]

583.两个字符串的删除操作(遇到不同字母就要删除,可以从左上角也可以从左边或者上边执行删除操作;解法二:找公共子序列,根据两字符串长度和公共子序列长度,计算最少操作数)

点击查看代码
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # 解法一:当word1的某个字符和word2某个字符不同时,可以删除其中一个;最终删除个数就是最小步数
        # 动态规划,dp[i][j]代表要使得word1的前i-1和word2的前j-1相同,要删除的最小步数
        # 构造二维dp数组
        dp = [[0]*(len(word2)+1) for _ in range(len(word1)+1)]
        # 初始化
        for i in range(len(word1)+1):
            dp[i][0] = i      # 相当于要一个i-1为结尾的word1片段与空字符串一样,那就得删除从0到i-1就是i个数
        for j in range(len(word2)+1):
            dp[0][j] = j
        # 开始遍历
        for i in range(1, len(word1)+1):
            for j in range(1, len(word2)+1):
                # 判断依据
                if word1[i-1] == word2[j-1]:
                    # 递推公式
                    dp[i][j] = dp[i-1][j-1]    # 相同那就啥都不用删除,操作次数跟左上角的一样
                else:
                    # 不同,就要删除一次;比如i-1,j-1的可以从左边i,j-1删除i-1这个元素
                    dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+2)
        return dp[-1][-1]

        # 解法二:找到word1和word2的公共子序列,最小步数=len(word1)+len(word2)-len(公共子序列)  # 好像是?
        # (略)
        

72.编辑距离(当两字母一样,则操作上等于左上角;若两字母不同,可能执行插入、删除或者替换,这几个就是在左上角或者左边或者上边的基础上加一)

点击查看代码
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # 用简单例子来说明插入、删除和替换
        # eg1. ab和a,可以前者删除b,也可以后者添加a
        # eg2. ab和ac,就用替换,两者中任意一个替换最后一个字母

        # 动态规划二维dp数组,dp[i][j]代表word1的前i-1段和word2的前j-1段要达到相同需要的最小操作数
        # 构造dp数组
        dp = [[0]*(len(word2)+1) for _ in range(len(word1)+1)]
        # 初始化dp数组的第一行第一列
        for i in range(len(word1)+1):
            dp[i][0] = i     # word1的前i-1段删除所有字母将等于后者空字符串
        for j in range(1, len(word2)+1):
            dp[0][j] = j
        # 开始遍历
        for i in range(1, len(word1)+1):
            for j in range(1, len(word2)+1):
                # 判断条件
                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, dp[i-1][j-1]+1)
        return dp[-1][-1]
        
        

PS:循序渐进,能一点一点理解了,卡尔这排序牛啊
今天阴转多云,开心,吃了大盘鸡、醉鸡、干锅蛙,今天太丰盛了,家里柚子又长虫眼可惜咯

标签:583,删除,随想录,len,115,range,word1,word2,dp
From: https://www.cnblogs.com/tristan241001/p/18544960

相关文章

  • 代码随想录:二分查找
    代码随想录:二分查找二分法标志:数组顺序排列且无重复简单的二分法,写法是左闭右闭的写法,此种情况的left可以等于right,故while里有等号。classSolution{public:intsearch(vector<int>&nums,inttarget){intleft=0;intright=nums.size()-1;......
  • 代码随想录:移除元素
    代码随想录:移除元素题目中的原地指的是不能开创新的数组。简单双指针解决问题,实际上是vector中的erase的实现原理//erase和迭代器的使用方法std::vector<int>vec={1,2,3,4,5};autoit=vec.begin()+2;//指向元素3//这所谓迭代器其实就是封装后的指针啊vec.era......
  • 代码随想录算法训练营第二十五天| leetcode491.递增子序列、leetcode46.全排列、leetc
    1leetcode491.递增子序列题目链接:491.非递减子序列-力扣(LeetCode)文章链接:代码随想录视频链接:回溯算法精讲,树层去重与树枝去重|LeetCode:491.递增子序列_哔哩哔哩_bilibili思路:用之前的方法,结果翻车了,好好看视频学新技能吧1.1视频后的思路真的没想到用set来去重,还是基......
  • 代码随想录算法训练营 | 所有可达路径
    所有可达路径文章链接:https://programmercarl.com/kamacoder/0098.所有可达路径.html#本题代码题目链接:https://kamacoder.com/problempage.php?pid=1170#include<iostream>#include<vector>usingnamespacestd;//全局路径vector<vector<int>>paths;vector<in......
  • 代码随想录算法训练营第二十四天| leetcode93.复原IP地址、 leetcode78.子集、leetcod
    1leetcode93.复原IP地址题目链接:93.复原IP地址-力扣(LeetCode)文章链接:代码随想录视频链接:回溯算法如何分割字符串并判断是合法IP?|LeetCode:93.复原IP地址_哔哩哔哩_bilibili思路:就是将这个字符串符合要求的进行一个收集,然后使用列表存储,最后使用join函数将这个列表进行连......
  • 代码随想录——二叉树17-路径总和
    这两道题目对于递归函数的返回值是不同的,这里进行总结,二叉树遍历中递归函数返回值何时有何时没有。这里总结如下三点:如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是路径总和ii)如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需......
  • 代码随想录算法训练营第二十三天| leetcode39. 组合总和、leetcode40.组合总和II、lee
    1leetcode39.组合总和题目链接:39.组合总和-力扣(LeetCode)文章链接:代码随想录视频链接:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)|回溯法精讲!_哔哩哔哩_bilibili思路:跟之前差不多,就是将他的循环改一下,但是我发现有重复的数值了,不知道如何删除1.1自......
  • 代码随想录算法训练营第十一天|LeetCode150.逆波兰表达式求值、239.滑动窗口最大值、3
    前言打卡代码随想录算法训练营第49期第十一天 φ(゜▽゜*)♪首先十分推荐学算法的同学可以先了解一下代码随想录,可以在B站卡哥B站账号、代码随想录官方网站代码随想录了解,卡哥清晰易懂的算法教学让我直接果断关注,也十分有缘和第49期的训练营大家庭一起进步。今日题目在学......
  • 代码随想录 -- 动态规划 -- 完全背包理论基础
    52.携带研究材料(第七期模拟笔试)思路:dp[j]的含义:装满容量为j的背包时,背包的最大价值为dp[j].递推公式:当j>=weight[i]时:dp[j]=max(dp[j],dp[j-weight[i]]+value[i])初始化:全部初始化为0遍历顺序:先遍历物品和先遍历背包都可以,都是从前往后遍历(因为物品可以重复使用)。n,......
  • 代码随想录第八天|字符串part01--344.反转字符串、541.反转字符串Ⅱ、卡玛网54.替换数
    资源引用:leetcode题目:344.反转字符串(344.反转字符串-力扣(LeetCode))541.反转字符串Ⅱ(541.反转字符串II-力扣(LeetCode))卡玛网题目:卡玛网54.替换数字(54.替换数字(第八期模拟笔试)(kamacoder.com))碎碎念回归:本来应该11月6号打卡的,因为接连4天的考试+多个竞赛,导致推迟......