LeetCode精讲题 10正则表达式匹配(动态规划)
标题
- 题目描述
- 递归(超时)
- 动态规划
- 结语
题目描述
先点赞再观看、帅哥靓女养成好习惯。
10 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和
'*'
的正则表达式匹配。
'.'
匹配任意单个字符
'*'
匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
输入:
s = “aa”
p ="a"
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p ="a*"
输出: true
解释: 因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释:".*"
表示可匹配零个或多个('*')
任意字符('.')
。
示例 4:
输入:
s = “aab”
p = “cab”
输出: true
解释: 因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p ="mis*is*p*."
输出: false
递归(超时)
这题刚开始见到,还以为遇到原题了,因为跟剑指offer的其中一题非常像,剑指offer第52题正则表达式,只不过那题给的两个char类型的数组,当时弱弱的用递归暴力过了。
然后一顿操作把上次递归的方法重写过来,结果超时了……
但是还是把这种递归的思路讲一下,递归主要进行匹配所有情况,主要是看当前位置两个串串能不能匹配。
需要考虑*
情况可以匹配,因为*
可以出现0次,1次多次。那么在遇到使用*
的如果匹配了,可以通过递归实现下面三者方式
- 它可以使用0次(相当于跟字符串下一部分匹配
a*aa
和aa
这个第一个a*
可以看成0次) - 也可以使用1次(在当前往后移例如
a*aa
和aaa
转成aa
和aa
的匹配) - 也可以使用多次(例如
a*
和aaa
转成a*
和aa
的匹配)
同样,如果遇到*
不可以匹配,那么就使用0次就行了(b*aa
和aa
匹配转换成aa
和aa
匹配)
如果下一个不是*
,那就考虑是否相当或者模式字符是否为.
进行继续匹配或者终止就可以,在考虑一些开始结束情况就可以了,一个大概的思维导图可以看一下。
这部分实现的代码如下:
public static boolean isMatch2(String s, String p) {//System.out.println(s+" "+p);if (p.length() == 0)// 模式串为false{if (s.length() == 0)return true;return false;} else if (s.length() == 0) {// 匹配串为0if (p.length() % 2 == 1)return false;else {for (int i = 1; i < p.length(); i += 2) {if (p.charAt(i) != '*')return false;}return true;}} else if (p.length() == 1) {//匹配串长度为1if((s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')&&s.length()==1)//可以匹配return true;else {return false;}} else {// 两个串串正常长度if(p.charAt(1)=='*')//下一个为*{if(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')//可以匹配 分别用0次 用若1次 用若干次{return isMatch(s.substring(1), p)||isMatch(s.substring(1), p.substring(2))||isMatch(s, p.substring(2));}else {//不匹配只能用0次return isMatch(s, p.substring(2));} }else {if(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.')return isMatch(s.substring(1), p.substring(1));else {//完全失败return false;}}}
很遗憾的超时了,不过在剑指offer是可以过的,主要遇到这种字符就会很麻烦:
isMatch("aaaaaaaaaaaaab", "a*a*a*a*a*a*a*a*a*a*c")
因为这里面匹配中的a*任意一个都可以使用若干次导致递归种类太多爆栈。嘤嘤嘤。
动态规划
这题正确而大众的解法当然是动态规划了,我们知道动态规划重在动态的规划方程。并且当前结果是基于父结果的。这题刚好就可以使用动态规划来解答。
我们使用我们声明一个dp[][]=new boolean[匹配串长度+1][模式串长度+1]
的二位数组用来储存结果, 其中dp[i][j]
表示匹配串前i个和模式串前j个是否匹配。最终匹配串和模式串是否匹配就是返回dp[匹配串长度][模式串长度]
.
对于动态规划的问题,我们一般会空余出0号位放在越界等特殊情况,所以我们声明的二维数组大小长宽都大1,因为0号在dp[][]
表示的是空串的结果而不是一号位置串的结果。然后我们在搞动态规划题一般需要以下几步:
- 声明dp数组,理解其含义
- 声明一些初始情况(一般为0)
- 找正常情况动态方程式
这里的初始我们是dp[0][0]=true
表示两个空串可以匹配。
我们分析这个dp[i][j]
匹配串前i个,模式串前j个是否匹配.其实这个分析和之前递归还是有点相似的:
首先如果模式串pattern第j个如果是*
,以下两种情况任意一种匹配成功即可。
- 如果
dp[i][j-2]==true
那么dp[i][j]
肯定为true,因为可以把它看成一个空串。
- 如果
dp[i][j-2]
不为true也不要紧,如果匹配串和模式串前一个字符可以匹配并且dp[i-1][j]
为true,那么也可以匹配(a*
和a
)
如果模式串第j个不为*
那么就是常规匹配了,如果当前位置字符不匹配,那么就为false,如果当前位置匹配且dp[i-1][j-1]==true
那么dp[i][j]
就为true:
当然,以上所有考虑i-1的情况i不能等于0.
综上分析得到dp方程为:
if(模式串当前为*)
dp[i][j]==dp[i][j-2]||(dp[i-1][j]&&两串当前字符可以匹配)
else
dp[i][j]=dp[i-1][j-1]&&两串当前字符可以匹配
具体实现需要注意下标编号在字符串位置和dp下标的含义,具体实现的代码为:
public static boolean isMatch(String s, String p) {boolean dp[][]=new boolean[s.length()+1][p.length()+1];//默认为falsedp[0][0]=true;for(int i=0;i<=s.length();i++){for(int j=1;j<=p.length();j++){if(p.charAt(j-1)=='*')//该位置为*{dp[i][j]=dp[i][j-2];//模式用了0次的看看是否能够匹配,能匹配最好,不能匹配继续if(!dp[i][j])//不能匹配{if(i==0) {continue;}else if(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)=='.')//可以匹配{dp[i][j]=dp[i-1][j];}}}else {//正常字符if(i==0){continue;}else if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.') {//这个位置可以匹配dp[i][j]=dp[i-1][j-1];}} }}return dp[s.length()][p.length()];
}
结语
今天又get一个动态规划题,以前没有用动态规划的思维去想过,但是这题还是挺好的,至于一些其他的方法如果后面有时间可以继续拓展。
原创不易,最后我请你帮两件事帮忙一下:
star支持一下, 您的肯定是我在平台创作的源源动力。
微信搜索「bigsai」,关注我的公众号,不仅免费送你电子书,我还会第一时间在公众号分享知识技术。加我还可拉你进力扣打卡群一起打卡LeetCode。
记得关注、咱们下次再见!
LeetCode精讲题 10正则表达式匹配(动态规划)相关推荐
- LeetCode 10.正则表达式匹配(动态规划)
题目描述 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '' 的正则表达式匹配. '.' 匹配任意单个字符 '' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字 ...
- [动态规划] leetcode 10 正则表达式匹配
[动态规划] leetcode 10 正则表达式匹配 1.题目 题目链接 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 ...
- Java实现 LeetCode 10 正则表达式匹配
10. 正则表达式匹配 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配, ...
- LeetCode算法复健:10.正则表达式匹配
10.正则表达式匹配 日期:2022/7/5 题目描述:给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 '*' 匹配零个或 ...
- LeetCode 10. 正则表达式匹配(递归/DP)
文章目录 1. 题目 2. 解题 2.1 递归 2.2 DP 1. 题目 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 ...
- leetcode 10 --- 正则表达式匹配
1 题目 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 ...
- [Leetcode][第44题][JAVA][通配符匹配][贪心][动态规划]
[问题描述][困难] [解答思路] 1. 动态规划 第 1 步:设计状态 dp[i][j]dp[i][j] 表示字符串 ss 的前 ii 个字符和模式 pp 的前 jj 个字符是否能匹配 第 2 步: ...
- LeetCode 10 正则表达式匹配
https://leetcode-cn.com/problems/regular-expression-matching/ 解决方案 class Solution {public boolean is ...
- 文巾解题 10. 正则表达式匹配
1 题目描述 2 解题思路 题目中的匹配是一个逐步匹配的过程:我们每次从字符串 p 中取出一个字符或者一个字符 & 星号的组合,并在 s 中进行匹配. 对于 p 中一个字符而言(包括字符.), ...
最新文章
- 一份520页的机器学习笔记!附下载链接
- 企业网络推广专员浅析是否网站权重越高企业网络推广效果越好?
- XMLHttpRequest
- 从本地的win传文件到本地的linux上,pscp.exe实现本地windows下的文件下载(传输)到linux上...
- 巧用TensorFlow实现图像处理
- 从JS敏感信息泄露到GETSHELL
- dataframe转化为array_【Python专栏】12 种高效 Numpy 和 Pandas 函数为你加速分析
- 跳出内层循环 使用 for of 代替 map
- 蓝桥杯第七届决赛之---阶乘位数
- 【MyBatis框架】配置文件-resultMap总结
- 支付宝最不想看到的:当“集五福”变成赚钱生意 有人日入千元!
- Centos5上安装JRE和LUMAQQ
- Android 用户可以直接在搜索页面上安装 app 了
- php工程师等级划分,PCB工程师的这四个等级,你都修炼到了什么级别?
- 倍福--TwinSAFE的配置
- 大数据(线性/非线性)降维方法(PCA,LDA,MDS,ISOMAP,LLE)
- php ml 非线性回归,科学网—非线性回归(迭代法)及其两种拟合曲线:y=a+b*exp(c*x) - 梅卫平的博文...
- 计算机操作员高级图形图像处理photoshopcs2试题解答,图形图像处理(Photoshop平台)Photoshop CS2试题汇编(图像制作员...
- 云呐|仓库RFID固定资产盘点软件有哪些优势
- 基于SSM+Vue的电影售票系统Java电影院票务管理系统电影订票系统(源码调试+讲解+文档)