Leetcode:正则表达式匹配

目录

普通版本(动态规划)

状态表示

状态转移方程

优化③①情况

数学化简分析

结合实际情况画图化简分析

总结

最终代码


题目链接:10. 正则表达式匹配 - 力扣(LeetCode)

好像是leetcode前100道里面最难的一道?我是fw🤡

普通版本(动态规划)

题目条件:

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素(将其理解为*号,某字符*表示可以有n个该字符)
  • 每次出现字符 * 时,前面都匹配到有效的字符(只有a~z*、.*两种情况)

注意事项:字符*,变化的多出来的字符是向后延申的

条件解析与示例分析:

示例1:s = "aa"、p = "a",可匹配

示例2:s = "aa"、p = "a*",a*是一个整体,可以表示0~n个a,可匹配

示例3:s = "ab"、p = ".*",.*是一个整体,可以表示0~n个.,每个.可代表任意字符,可匹配

示例4:s = "aab"、p = "d*a*b",将d*视为一个空串,a*表示两个a,b不变,可匹配

状态表示

分析:由题意得我们可以要判断的是p中[0,j]范围内的字符是否能匹配s中[0,i]范围内的字符,涉及了两个数组间情况得判断

结论:状态转移方程为dp[i][j],该方程表示p[0,j]范围内的子串是否可以匹配s[0,j]范围内的子串 

状态转移方程

主旨:根据p数组最后位置的取值进行分情况讨论(s[i]和p[j]分别表示s和p数组最后位置的字符)

①p[j]是a~z的字符

满足  p[j] == s[i] && dp[i-1][j-1] == true 时dp[i][j]为真(当前和之前所有位置都为真)

②p[j]是字符.

满足dp[i-1][j-1]==true,则dp[i][j]为真(只要之前均为真,.必可使最后一个位置也相同)

③p[j]是* 

③①p[j-1]是.

③①①.*表示空串

  • 此时p[j-1]和p[j]位置报废,若dp[i][j-2]为真则dp[i][j]为真,即p的[0,j-2]范围内的字符能否与s的[0,i]范围内的字符匹配

③①②.*表示一个.

  • 此时p[j]位置报废p[j-1]位置为.若dp[i-1][j-2]为真则dp[i][j]为真,即p的[0,j-2]范围内的字符能否与s的[0,i-1]范围内的字符匹配,因为p[j-1]位置的.能表示任意字符,故s[i-1]位置不论是什么字符dp[i-1][j-1]一定为真

③①③.*表示两个.

  • 此时p[j]和p[j-1]位置均为.若dp[i-2][j-2]为真则dp[i][j]为真,即p的[0,j-2]范围内的字符能否与s的[0,i-2]范围内的字符匹配,因为p[j]和p[j-1]位置的.能表示任意字符,故s[i]h和s[i-1]位置不论是什么字符dp[i][j]和dp[i-1][j-1]一定为真

③①④.*表示三个.

  • 此时p[j]和p[j-1]均为甚至p[j+1]位置均为.若dp[i-3][j-2]为真则dp[i][j]为真,即p的[0,j-2]范围内的字符能否与s的[0,i-3]范围内的字符匹配...(都一样不重复解释了)

p[j-1]是a~z的字符

②①字符*表示空串

  • 此时p[j-1]和p[j]位置报废,若dp[i][j-2]为真则dp[i][j]为真(与上面一样了,不解释了)

③②②判断j-1位置的字符是否与i位置相同(p[j-1] == s[i])

  • 相同则保留字符*的状态,此时若dp[i-1][j]为真则dp[i][j]为真因为s[j-1]位置上的字符与i位置匹配后因为可以用*造出很多个该字符,所以只需考虑p[0,j]范围内的字符能否与s[0,i-1]范围内的字符匹配即可(而判断这一个范围内的情况,就需要再次到③②②这种情况来进行判断),如果均匹配则让*造字符时多加一个该字符即可

优化③①情况

优化结果:当p[j]为*、p[j-1]为.时,dp[i][j] = dp[i][j-2] || dp[i-1][j]

初步分析:由③①中的多条结论可以得出,当满足其中一个结论时,dp[i][j]就为真,因为此时p[j-1]和p[j]的组合为.*,如果dp[i][j-2]为真,那么.*只需要创建出一个.即可,如果dp[i-3][j-2]为真,那么.*只需要创建出三个.即可,即只要前面的相等,后面的.*就绝对可以保证后面的所有都相等,即:①p[j] == '*'时,dp[i][j] = dp[i][j-2] ||  dp[i-1][j-2] || dp[i-2][j-2] ...,但是这个式子还是有点长,那么是否能继续化简一下?

数学化简分析

我们令i=i-1,重新套入上面的式子可得:

②p[j] == '*'时,dp[i-1][j] = dp[i-1][j-2] ||  dp[i-2][j-2] || dp[i-3][j-2] ...

我们发现,满足dp[i-1][j]为真需要满足dp[i-1][j-2] ||  dp[i-2][j-2] || dp[i-3][j-2] ...的某个条件为真,而该条件与①中的后半部分完全相同,由简单的数学等价替换就可以得到我们优化③①情况的优化结果

结合实际情况画图化简分析

当p[j]为*、p[j-1]为.时,我们可以分为两种情况:

情况一:当.*组合与s[i]相同后后不变化仍然保留.*组合,接着比较s[i-1],如果dp[i-1][j]为真则dp[i][j]为真(s的[0,i-1]范围内的字符与p[0,j]范围内的字符可以匹配)

情况二:将.*视为一个空串,那么此时如果dp[i][j-2]为真,则dp[i][j]也就为真

总结

1、①和②可以总结为一种情况:当p[j]==s[i] 或者 p[j]==. 为真 且dp[i-1][j-1]为真(两个的末尾都匹配了 或者 p的末尾为.时无论s的末尾为什么字符都能匹配),那么dp[i][j]就为真

2、③可以总结为:当 dp[i][j-2] 为真或者 (p[j-1] == '.' || p[j-1] == s[i])一个为真且 dp[i-1][j] 为真,则dp[i][j]为真(整合后p[j]==*时引发的所有结论,可以发现这些结论的本质就是围绕p[j-1]*的组合是空串还是非空串进行研究并得出结论的)

  • p[j-1]*的组合为空:由上图的分析得,当p[j]为*时一定有“某字符*”是空串的情况,故可以将③①和③②为空的情况合并得到判断dp[i][j]是否为空的一个条件dp[i][j-2]
  • p[j-1]*的组合不为空:当p[j-1]为.时该组合为“.*”,此时只要dp[i-1][j]为真即可(上面优化里的当dp[j]为*、p[j-1]为.时dp[i][j]为真的两个条件dp[i][j-2] || dp[i-1][j],p[j-1]*组合为空时候占用了一个dp[i][j-2],现在就剩下另一个条件了,当然如果你不信也可以再推一遍),当p[j-1]为a~z的字符时该组合为“a~z的字符*”,此时也是只需要dp[i-1][j]为真即可

最终代码

class Solution {
public:bool isMatch(string s, string p) {int m = s.size(),n = p.size();//二者大小不一样相同//1、创建dp表vector<vector<bool>> dp(m+1,vector<bool>(n+1));//创建一个m行n列的dp表,+1是为了创建辅助行//2、初始化s = ' ' + s,p = ' ' + p;//加上一行辅助位,此时字符串下标和dp表下标一致,不需要在填表时做下标-1的操作//先填写左上角的辅助行为true,处理特殊情况,即当s为空时,根据p中字符*的情况得到匹配结果(准备工作)dp[0][0] =true;//更新dp表for(int j = 2;j<=n;j+=2)if(p[j]=='*') dp[0][j] =true;else break;//3、填表for(int i = 1;i <= m;i++){for(int j = 1;j <= n;j++){//p[j]为*L:③的所有情况得到的结论if(p[j] == '*'){dp[i][j] = dp[i][j-2] || (p[j-1] == '.' || p[j-1] == s[i]) && dp[i-1][j];}//p[j]不为*:①②两种情况得到的结论else{dp[i][j] = (p[j] == s[i] || p[j] == '.')&&dp[i-1][j-1];}}}//4、返回值return dp[m][n];//题目要求的是完全匹配,所以判断范围为[0,m]和[0,n];}
};

自我总结:动规主要的内容就是确认状态表示和状态转移方程,由特例推广至全部,只需要直到宏观规律即可

~over~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/21151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHAR反序列化

PHAR PHAR&#xff08;PHP Archive&#xff09;文件是一种归档文件格式&#xff0c;phar文件本质上是一种压缩文件&#xff0c;会以序列化的形式存储用户自定义的meta-data。当受影响的文件操作函数调用phar文件时&#xff0c;会自动反序列化meta-data内的内容,这里就是我们反序…

jmeter常用的断言

包括&#xff08;Contains&#xff09;&#xff1a;响应内容包括需要匹配的内容即代表响应成功&#xff0c;支持正则表达式 匹配&#xff08;Matches&#xff09;&#xff1a;响应内容要完全匹配需要匹配的内容即代表响应成功&#xff0c;大小写不敏感&#xff0c;支持正则表达…

Windows安装ElasticSearch版本7.17.0

在Windows系统上本地安装Elasticsearch的详细步骤如下&#xff1a; 1. 下载Elasticsearch 访问 Elasticsearch下载页面。选择适用于Windows的版本7.17.0&#xff0c;并下载ZIP文件。 2. 解压文件 下载完成后&#xff0c;找到ZIP文件&#xff08;例如 elasticsearch-7.17.0.…

spoon基础使用-第一个转换文件

新建一个转换&#xff0c;文件->新建->转换&#xff0c;也可以直接ctralN新建。 从右边主对象树拖拽一个输入->表输入&#xff1b;输出->文本文档输出&#xff1b;也可以直接在搜索框搜素表输入、文本文档输出。 双击表输入新建一个数据库连接 确定后就可以在S…

【人工智能】第二部分:ChatGPT的架构设计和训练过程

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Java | Leetcode Java题解之第126题单词接龙II

题目&#xff1a; 题解&#xff1a; class Solution {public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {List<List<String>> res new ArrayList<>();// 因为需要快速判断扩展出的单词…

传输中的串扰(八)

串扰指的是有害信号从一个线网传递到相邻线网上。通常把噪声源所在的线网称为动态线或攻击线网&#xff0c;而把有噪声形成的线网称为静态线或受害线网。 静态线上的噪声电压的表现与信号电压完全一样。一旦在静态线上产生噪声电压&#xff0c;它们就会传播并在阻抗突变处出现反…

常见算法(基本查找、二分查找、分块查找冒泡、选择、插入、快速排序和递归算法)

一、常见算法-01-基本、二分、插值和斐波那契查找 1、基本查找/顺序查找 需求1&#xff1a;定义一个方法利用基本查找&#xff0c;查询某个元素是否存在 数据如下&#xff1a;{131&#xff0c;127&#xff0c;147&#xff0c;81&#xff0c;103&#xff0c;23&#xff0c;7&am…

C++ C (1152) : 循环赛日程表

文章目录 一、题目描述二、参考代码 一、题目描述 二、参考代码 #include<iostream> #include<vector> #include<cstdlib> using namespace std;void generateSchedule(vector< vector<int> >& table, int numPlayers, int rounds) {// 生…

堆排序-java

这次主要讲了堆排序和堆的基本构造&#xff0c;下一期会详细讲述堆的各种基本操作。 文章目录 前言 一、堆排序 1.题目描述 2.堆 二、算法思路 1.堆的存储 2. 结点下移down 3.结点上移up 4.堆的基本操作 5.堆的初始化 三、代码如下 1.代码如下&#xff1a; 2.读入数据&#xff…

小公司的软件开发IT工具箱

目录 工具链困境 难题的解决 达到的效果 资源要求低 工具箱一览 1、代码管理工具 2、自动化发版&#xff08;测试&#xff09;工具 3、依赖库&#xff08;制品包&#xff09;管理 4、镜像管理 5、授权管理&#xff08;可选&#xff09; 待讨论&#xff1a;为什么不是…

LeetCode17电话号码的字母组合

题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 解析 广度优先遍历或者深度优先遍历两种方式&#xff0c;广度优先…

渗透测试靶机----FirstLeads_1.3

渗透测试靶机----FirstLeads_1.3 启动靶机&#xff0c;扫描ip&#xff0c;平平无奇 可以看出&#xff0c;这里是存在139这个主机的&#xff0c;这就是扫描出来的靶机ip继续探测端口及其他信息 发现这里只开启了80 端口 尝试一些基本目录&#xff0c;发现存在robot.txt文件目录…

集成算法:Bagging模型、AdaBoost模型和Stacking模型

概述 目的&#xff1a;让机器学习效果更好&#xff0c;单个不行&#xff0c;集成多个 集成算法 Bagging&#xff1a;训练多个分类器取平均 f ( x ) 1 / M ∑ m 1 M f m ( x ) f(x)1/M\sum^M_{m1}{f_m(x)} f(x)1/M∑m1M​fm​(x) Boosting&#xff1a;从弱学习器开始加强&am…

插入排序以及希尔排序; 先学会插入,希尔会更简单喔

1.前言 首先肯定是要学会插入排序再学习希尔排序会更简单&#xff0c;因为代码部分有很多相似之处&#xff1b;如果你觉得你很强&#xff0c;可以直接看希尔排序的讲解。哈哈哈&#xff01;&#xff0c;每天进步一点点&#xff0c;和昨天的自己比 2.插入排序 让我们先来看看…

鸿蒙Ability Kit(程序框架服务)【UIAbility组件与UI的数据同步】

UIAbility组件与UI的数据同步 基于当前的应用模型&#xff0c;可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 [使用EventHub进行数据通信]&#xff1a;在基类Context中提供了EventHub对象&#xff0c;可以通过发布订阅方式来实现事件的传递。在事件传递前&am…

Rustdesk 自建服务器教程

一、环境 阿里云轻量服务器、debian11 系统 二、服务端搭建 2.1、开放防火墙指定端口 TCP(21115, 21116, 21117, 21118, 21119)UDP(21116) 2.2、安装 rustdesk 服务器文件 在 github 下载页https://github.com/rustdesk/rustdesk-server/releases/&#xff0c;下载 rustde…

【自撰写,国际象棋入门】第1课、棋盘和棋子

第1课 棋盘和棋子 一、国际象棋的棋盘 国际象棋的棋盘为一8乘8的黑、白格相间的棋盘&#xff0c;8条竖线的编号分别为A-H&#xff0c;8条横线的编号分别为1-8&#xff0c;在记谱时用竖线编号横线编号的方式表示棋盘上的格子&#xff0c;例如a1格、h8格等.棋盘上有几条重要的大…

c++程序员为什么要做自己的底层库

五一期间&#xff0c;在家里翻到之前上学时候用的电脑和工作日志&#xff0c;粗略浏览一番&#xff0c;感慨10年岁月蹉跎&#xff0c;仍然没有找到自己技术方向的“道”。遂有感而发&#xff0c;写下此文。 算起来&#xff0c;接触软件开发也有10年时间了&#xff0c;最开始是…

Java——异常

1.什么是异常 将程序执行过程中发生的不正常行为称为异常。 常见的异常有&#xff1a;算数异常&#xff0c;空指针异常&#xff0c;数组越界异常 每一种异常都有对应的类对齐描述 为了对每一种异常进行管理&#xff0c;Java内部实现了一个对异常的体系结构 1. Throwable&#x…