前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >动态规划:字符串匹配

动态规划:字符串匹配

作者头像
鹏-程-万-里
发布于 2020-04-30 10:40:03
发布于 2020-04-30 10:40:03
1.3K00
代码可运行
举报
运行总次数:0
代码可运行

各位小伙伴大家好~本周我们来介绍两道字符串相关的题目,主要是使用动态规划来进行匹配解题。

在开始之前,我们聊一聊动态规划。其实动态规划看到底也是属于穷举算法。我们将所有的可能性都列举出来,然后在所有的可能性中选择一个最优解即可。但是同样是穷举,为啥我们使用迭代的时候容易超时呢?主要在于动态规划带有一定的记忆。当我们使用迭代的时候,有很多子问题被我们重复计算,但是动态规划却将每一次的子问题进行了一个简单的存储,类似于备忘录。当遇到子问题的时候,我们先到备忘录中寻找之前有没有遇到过相同的子问题,如果遇到过,那么我们就直接从备忘录中取出结果返回即可。这样就可以有效避免对子问题的重复计算,大大提升效率。

所以一般遇到最值问题,或者多种可能性,选择最优解的时候,我们可以往动态规划上去想。下面我们来分享两道题目。

编辑距离

❝LeetCode72 --- 编辑距离【困难】 题目描述 ❞

题目描述

1、解题思路

根据题目,为了匹配字符串,我们需要将其中一个字符串修改为另一个字符串,其中的操作主要有3种,替换,插入,和删除。我们需要找到最少的修改次数。

由于属于求最值问题,需要遍历所有的可能,所以我们首选动态规划。

  1. 关于数组的定义:
    • 定义dp[i][j],将其表示为word1的前i个字符修改为word2的前j个字符时,所使用的最少次数;
  2. 关于初始化:
    • 第一列dp[i][0]表示word2为空的时候,那么我们将全部采取删除操作,所以此时对于dp[i][0] = i;
    • 第二列dp[0][j]表示word1为空时,我们将全部采取插入操作,对word1使用插入来达到最后的目标字符串,所以dp[0][j]=j;
  3. 关于状态方程:
    • 如果word1[i] == word2[j],那么此时,我们是不需要进行任何操作的,所以次数也是等于两个字符串上一次修改的次数,即dp[i][j] = dp[i-1][j-1]
    • 当两个字符串的字符不相同时,我们就可以对其选择进行题目中的三种操作:
    • 替换:替换之后的字符串将会与word1[i-1]word2[j-1]的字符串相同,所以对应的dp[i][j] = dp[i-1][j-1]+1;
    • 插入:插入之后的字符串将会与word1[i]word2[j-1]的字符串相同,所以对应的dp[i][j] =dp[i][j-1]+1
    • 删除:删除之后的字符串将会与word1[i-1]word2[j]的字符串相同,所以对应的dp[i][j] =dp[i-1][j]+1

对于三种操作,我们进行对比,选出最小值即可得到从word1[i]word2[j]的最小修改次数dp[i][j]

于是我们就可以进行动态规划的代码编写了~

2、代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public int minDistance(String word1, String word2) {
        
        int[][] dp = new int[word1.length() +1][word2.length() + 1];

        //代表着当word2 == " " 时,需要将word1中的每个字母逐个删除,将 word1 改造成为 word2
        for(int i = 1 ; i <= word1.length() ; i++){
            dp[i][0] += i; 
        }

        //代表当word1 == " " 时,需要逐个进行插入,得到一个 word2
        for(int j = 1 ; j <= word2.length() ; j++){
            dp[0][j] += j; 
        }

        for(int i = 1 ; i <= word1.length() ; i++ ){
            for(int j = 1 ; j <= word2.length() ; j++){
                if(word1.charAt(i-1) == word2.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = Math.min(dp[i-1][j-1],Math.min(dp[i-1][j],dp[i][j-1])) + 1;
                }
            }
        }

        return dp[word1.length()][word2.length()];
    }

通配符匹配

❝LeetCode44 --- 通配符匹配【困难】 题目描述 ❞

题目描述

1、解题思路

这道题目,依然是两个字符串,需要我们来记录两者是否能够相互匹配。那么我们还是需要列举出所有的情况,那么我们还是优先考虑动态规划。

有了上面的编辑距离的铺垫,我们这次的类比应该会简单一点。

  1. 定义数组dp[i][j]
    • 将其申明为Boolean类型数组,定义dp[i][j]表示s[i]p[j]的匹配情况。
  2. 下面对其进行初始化:
    • dp[0][0]:表示当s和p都为空时,两者匹配成功,所以dp[0][0] = true
    • 第一列:表示当p为空时,s[i]与p的匹配状态,此时当然全部都为false
    • 第一行:表示当s为空时,p[j]与s的匹配状态,在这种情况下,只有p[j]之前的所有的字符均为星号时,才可以匹配成功。

3.状态方程:

  • s[i] = p[j]时,此时的状态应该与s[i-1]p[j-1]的状态相同,所以此时dp[i][j] = dp[i-1][j-1];
  • p[j] = '*'时,此时的星号可以匹配一个空串,那么dp[i][j] = dp[i][j-1] ,同时也可以匹配多个字符串,此时dp[i][j] = dp[i-1][j],而我们只需要有一种能够匹配成功即可,所以dp[i][j] = dp[i][j-1] || dp[i-1][j]
  • 当上面的两种情况都不满足时,就代表当前的两种状态是不匹配的,所以dp[i][j]=false;

2、代码实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public boolean isMatch(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        boolean[][] dp = new boolean[sLen+1][pLen+1];

        //初始化,当s和p都为空的时候,为匹配成功
        dp[0][0] = true;
        
        //当s不为空,p为空时,dp[i][0]都为fasle
        //当p的每个字符否为星号时,才可以对空串s匹配成功
        for(int j = 1 ; j <= pLen ; j++){
            dp[0][j] = dp[0][j-1] && p.charAt(j-1) == '*';
        }

        for(int i = 1 ; i <= sLen ; i++){
            for(int j = 1 ; j <= pLen ; j++){
                if(s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '?'){
                    dp[i][j] = dp[i-1][j-1];
                }else if(p.charAt(j-1) == '*'){
                    //此时表示将星号匹配前一个字符,或者匹配空串
                    dp[i][j] = (dp[i-1][j] || dp[i][j-1]);
                }
            }
        }
        return dp[sLen][pLen];
    }
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java小白成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
力扣每日一刷(2023.9.21)
本题其实不使用动态规划的思路也是能够解出来的 ,并且时间复杂度 和 空间复杂度更低。 因为题目中问的是 s 是否为t 的自序列, 我们自需要顺序遍历 t ,然后对比是否 s中也出现, 并且相对顺序不能变更即可。 代码实现中有。
用户11097514
2024/05/31
920
力扣每日一刷(2023.9.21)
搞定大厂算法面试之leetcode精讲3.动态规划
动态规划,英文:Dynamic Programming,简称DP,将问题分解为互相重叠的子问题,通过反复求解子问题来解决原问题就是动态规划,如果某一问题有很多重叠子问题,使用动态规划来解是比较有效的。
全栈潇晨
2021/11/22
4130
搞定大厂算法面试之leetcode精讲3.动态规划
面试必备:高频算法题汇总「图文解析 + 教学视频 + 范例代码」之 字符串处理+动态规划 合集!
秋招接近尾声,我总结了 牛客、WanAndroid 上,有关笔试面经的帖子中出现的算法题,结合往年考题写了这一系列文章,所有文章均与 LeetCode 进行核对、测试。欢迎食用
圆号本昊
2021/09/24
5310
面试必备:高频算法题汇总「图文解析 + 教学视频 + 范例代码」之 字符串处理+动态规划 合集!
LeetCode-面试题19-正则表达式匹配
给你一个字符串s和一个字符规律p,请你来实现一个支持 '.'和'*'的正则表达式匹配。
benym
2022/07/14
1990
精读《算法题 - 编辑距离》
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数。
黄子毅
2023/10/25
2350
精读《算法题 - 编辑距离》
动态规划之终极绝杀:编辑距离
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
代码随想录
2021/04/08
5610
一招解决4道leetcode hard题,动态规划在字符串匹配问题中的应用
在做leetcode的时候,遇到hard题大家往往都觉得头疼,但其实,掌握方法,举一反三,hard题有时候我们也能想到好的思路,顺利攻破,今天我们就介绍一下动态规划在字符串匹配中的应用,相同类型的题目在前120道题中居然出现了4次!有必要好好总结一下! 这四道题分别是: 10. Regular Expression Matching:https://leetcode.com/problems/regular-expression-matching/description. 44.Wildcard Match
石晓文
2018/04/11
4.7K0
一招解决4道leetcode hard题,动态规划在字符串匹配问题中的应用
Leetcode No.72 编辑距离(动态规划)
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
week
2021/11/29
3750
Leetcode No.72 编辑距离(动态规划)
算法刷题-戳气球(数组、动态规划)、Pow(x, n)(递归、数学)、编辑距离(字符串、动态规划)
有 n 个气球,编号为0 到 n - 1,每个气球上都标有一个数字,这些数字存在数组 nums 中。 现在要求你戳破所有的气球。戳破第 i 个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i - 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界,那么就当它是一个数字为 1 的气球。 求所能获得硬币的最大数量。
共饮一杯无
2023/02/10
2600
常用算法思想之动态规划的后缀思想
思路:后缀是指要解决的子问题是原问题的后半部分,如果用字符串类描述,相当于子问题永远都是原问题的后半部分 str[i:]
爬蜥
2024/02/19
1670
常用算法思想之动态规划的后缀思想
动态规划 72. 编辑距离
给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
MashiroT
2023/01/30
1790
微软又考了这道题
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
五分钟学算法
2022/05/27
4370
微软又考了这道题
LeetCode 训练场:72. 编辑距离
示例 1: **输入:**word1 = “horse”, word2 = “ros” **输出:**3 解释: horse -> rorse (将 ‘h’ 替换为 ‘r’) rorse -> rose (删除 ‘r’) rose -> ros (删除 ‘e’) 示例 2: **输入:**word1 = “intention”, word2 = “execution” **输出:**5 解释: intention -> inention (删除 ‘t’) inention -> enention (将 ‘i’ 替换为 ‘e’) enention -> exention (将 ‘n’ 替换为 ‘x’) exention -> exection (将 ‘n’ 替换为 ‘c’) exection -> execution (插入 ‘u’)
村雨遥
2022/06/15
1370
583. 两个字符串的删除操作
给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。 示例: 输入: "sea", "eat" 输出: 2 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea" 给定单词的长度不超过500。 给定单词中的字符只含有小写字母。 class Solution { public int minDistance(String word1, String word2) {
编程张无忌
2021/06/29
7740
010. 正则表达式匹配 | Leetcode题解
给定一个字符串( s ) 和一个字符模式( p )。实现支持 '.' 和 '*' 的正则表达式匹配。
苏南
2020/12/16
2980
010. 正则表达式匹配 | Leetcode题解
72. 编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。
张伦聪zhangluncong
2022/10/26
3550
字符串的距离(动态规划) - leetcode 72
,因为在刷leetcode的动态规划专题。动态规划虽然定义很简单,但是对于复杂的动态规划题目,很多时候还是很棘手的。
ACM算法日常
2018/08/07
6810
字符串的距离(动态规划) - leetcode 72
动态规划设计
输入: [10,9,2,5,3,7,101,18] 输出: 4 解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
Tim在路上
2020/08/04
6250
LeetCode 09正则表达式匹配(递归VS动态规划)
这题刚开始见到,还以为遇到原题了,因为跟剑指offer的其中一题非常像,剑指offer第52题正则表达式,只不过那题给的两个char类型的数组,当时弱弱的用递归暴力过了。
bigsai
2020/08/21
4130
LeetCode 09正则表达式匹配(递归VS动态规划)
动态规划问题-LeetCode 91、72(动态规划方程)
一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 … 'Z' -> 26 给定一个只包含数字的非空字符串,请计算解码方法的总数。
算法工程师之路
2019/10/14
6030
相关推荐
力扣每日一刷(2023.9.21)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验