乘风破浪:LeetCode真题_010_Regular Expression Matching

乘风破浪:LeetCode真题_010_Regular Expression Matching

一、前言

    关于正则表达式我们使用得非常多,但是如果让我们自己写一个,却是有非常大的困难的,我们可能想到状态机,确定,非确定状态机确实是一种解决方法,不过需要消耗很大的时间去推理和计算,对于正则表达式的缩小版,我们往往可以通过递归,递推,动态规划等方法来解决。

二、Regular Expression Matching

2.1 问题理解

2.2 问题分析和解决

    遇到这样的问题,我们想到了递归,对于.是很好处理和匹配的,但是如果和*结合起来就变化无穷了,正是因为*我们才要递归。

    让我们看看官方的答案:

class Solution {public boolean isMatch(String text, String pattern) {if (pattern.isEmpty()) return text.isEmpty();boolean first_match = (!text.isEmpty() &&(pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));if (pattern.length() >= 2 && pattern.charAt(1) == '*'){return (isMatch(text, pattern.substring(2)) ||(first_match && isMatch(text.substring(1), pattern)));} else {return first_match && isMatch(text.substring(1), pattern.substring(1));}}
}

    如果模式串和源串第一个字符能够正常匹配,并且不为空,模式串的第二个字符不为'*',那么我们可以继续递归匹配下面的东西:

1 return first_match && isMatch(text.substring(1), pattern.substring(1));

    如果模式串的长度大于1,并且第二个字符是*,那么我们就有可能匹配到源串的很多的字符,也就相当于将源串已经匹配的去掉,拿剩下的和整个模式串继续比较,此时*发挥了作用,或者比较源串与去掉了*的模式串,因为*没有能够发挥作用。于是就得到了:

1         if (pattern.length() >= 2 && pattern.charAt(1) == '*'){
2             return (isMatch(text, pattern.substring(2)) ||
3                     (first_match && isMatch(text.substring(1), pattern)));
4         } 

     除此之外我们还可以使用动态规划算法:

class Solution {public boolean isMatch(String text, String pattern) {boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];dp[text.length()][pattern.length()] = true;for (int i = text.length(); i >= 0; i--){for (int j = pattern.length() - 1; j >= 0; j--){boolean first_match = (i < text.length() &&(pattern.charAt(j) == text.charAt(i) ||pattern.charAt(j) == '.'));if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];} else {dp[i][j] = first_match && dp[i+1][j+1];}}}return dp[0][0];}
}

     首先我们定义dp[i][j]代表源串T[i:]和模式串P[j:]是匹配的,其中i,j为源串和模式串的下标,于是我们只要求得dp[0][0]的值就可以了。我们已知的条件是:

 dp[text.length()][pattern.length()] = true;

     于是我们从后往前倒求最终的dp[0][0],通过如下的判断,看看是哪一种情况,然后根据相应的情况采取不同的递推策略,最终得到结果:

1    boolean first_match = (i < text.length() &&
2                             (pattern.charAt(j) == text.charAt(i) ||
3                             pattern.charAt(j) == '.'));
4    if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
5          dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
6    } else {
7          dp[i][j] = first_match && dp[i+1][j+1];
8    }

       同样的我们算法也是使用了递归和动态规划:

    在动态规划方面我们使用match[i]来表示对于源串从i到最后(T[i:])都是能够匹配的,于是之用求match[0]即可。

import java.util.Arrays;public class Solution {/*** Implement regular expression matching with support for '.' and '*'.* '.' Matches any single character.* '*' Matches zero or more of the preceding element.** 题目大意:* 实现一个正则表达式匹配算法,.匹配任意一个字符,*匹配0个或者多个前导字符*/public boolean isMatch(String s, String p) {boolean[] match = new boolean[s.length() + 1]; Arrays.fill(match, false);match[s.length()] = true;//刚开始满足需要for (int i = p.length() - 1; i >= 0; i--) {if (p.charAt(i) == '*') {for (int j = s.length() - 1; j >= 0; j--)  {
          //原来就是false只有能够为真,才为真。match[j] = match[j] || match[j + 1]&& (p.charAt(i - 1) == '.' || s.charAt(j) == p.charAt(i - 1));}i--;} else {for (int j = 0; j < s.length(); j++) {
//从前往后,只有到了已经有true的时候才能生效。如果从后往前反而有问题。 match[j] = match[j + 1]&& (p.charAt(i) == '.' || p.charAt(i) == s.charAt(j));}//将最后的置为假,本来就应该不真,便于以后的判断match[s.length()] = false;}}return match[0];}// 下面的代码用时比较长public boolean isMatch2(String s, String p) {// 输入都为nullif (s == null && p == null) {return true;}// 有一个为nullelse if (s == null || p == null) {return false;}return isMatch(s, 0, p, 0);}/*** 正则表达式匹配** @param s 匹配串* @param sIdx 当前匹配的位置* @param p 模式串* @param pIdx 模式串的匹配位置* @return 匹配结果*/public boolean isMatch(String s, int sIdx, String p, int pIdx) {// 同时到各自的末尾if (s.length() == sIdx && p.length() == pIdx) {return true;}// 当匹配串没有到达末尾,模式串已经到了末尾else if (s.length() != sIdx && p.length() == pIdx) {return false;}// 其它情况else {// 如果当前匹配的下一个字符是*号if (pIdx < p.length() - 1 && p.charAt(pIdx + 1) == '*') {// 匹配串未结束并且当前字符匹配(字符相等或者是.号)if (sIdx < s.length() && (s.charAt(sIdx) == p.charAt(pIdx) || p.charAt(pIdx) == '.')) {return isMatch(s, sIdx + 1, p, pIdx + 2) // 匹配串向前移动一个字符(只匹配一次)|| isMatch(s, sIdx + 1, p, pIdx) // 匹配串向前移动一个字符(下一次匹配同样的(模式串不动))|| isMatch(s, sIdx, p, pIdx + 2); // 忽略匹配的模式串} else {// 忽略*return isMatch(s, sIdx, p, pIdx + 2);}}// 匹配一个字符if (sIdx < s.length() && (s.charAt(sIdx) == p.charAt(pIdx) || p.charAt(pIdx) == '.')) {return isMatch(s, sIdx + 1, p, pIdx + 1);}}return false;}}

 

    如下表所示,使用递归需要1163ms而使用动态规划需要20ms,差别非常显著。

三、总结

     对于一些比较困难的问题,我们需要从不同的角度考虑,解决问题的方法可以从递归,递推,动态规划等方面去考虑。

转载于:https://www.cnblogs.com/zyrblog/p/10211390.html

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

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

相关文章

python——获取数据类型

在python中&#xff0c;可使用type()和isinstance()内置函数获取数据类型 如&#xff1a; &#xff08;1&#xff09;type()的使用方法&#xff1a;    >>> a 230 >>> type(a) <class str> >>> a 230 …

vue项目工程中npm run dev 到底做了什么

npm install 安装了webpack框架中package.json中所需要的依赖 2.安装完成之后&#xff0c;需要启动整个项目运行&#xff0c;npm run 其实执行了package.json中的script脚本&#xff0c;npm run dev的执行如下 3.底层相当执行webpack-dev-server --inline --progress --confi…

JavaScript回顾与学习——条件语句

一、if...else // if elsevar age 16;if(0 < age && age < 6){console.log("儿童");}else if(6 < age && age < 14){console.log("少年");}else if(14 < age && age < 35){console.log("青年");}els…

bat等大公司常考java多线程面试题

1、说说进程,线程,协程之间的区别 简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程.进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高.线程是进程的一个实体,是cpu调度和分派的基本单位,是比…

webpack.config.js和package.json

webpack.config.js 是webpakc的配置文件&#xff0c;webpack是当今很火的一个打包工具 使用webpack.config.js在你的项目里 可以对你的项目进行模块化打包&#xff0c;并且也可使组件按需加载&#xff0c;还可将图片变成base64格式减少网络请求。 而package.json 是指你项目的…

七牛云图片加载优化

?imageView2/2/w/80https://developer.qiniu.com/dora/manual/1279/basic-processing-images-imageview2 ?imageView2/1/w/80/h/80会裁剪 ?imageView2/3/w/80/h/80不会裁剪 转载于:https://www.cnblogs.com/smzd/p/9025393.html

org.apache.maven.archiver.mavenarchiver.getmanifest怎么解决

原因就是你的maven的配置文件不是最新的 1.help ->Install New Software -> add ->https://otto.takari.io/content/sites/m2e.extras/m2eclipse-mavenarchiver/0.17.2/N/LATEST 或者&#xff08;更新于2018年4月18日17:07:53&#xff09; http://repo1.maven.org/mav…

npm中package.json详解

通常我们使用npm init命令来创建一个npm程序时&#xff0c;会自动生成一个package.json文件。package.json文件会描述这个NPM包的所有相关信息&#xff0c;包括作者、简介、包依赖、构建等信息&#xff0c;格式是严格的JSON格式。 常用命令 npm i --save packageName 安装依赖…

offset系列,client系列,scroll系列回顾

一 scroll系列属性 ——滚动1 scrollHeight/scrollWidth 标签内部实际内容的高度/宽度ele.scrollHeight 有两种情况&#xff0c;当内容超出盒子范围后&#xff0c;返回的是内容的高度&#xff0c;包括padding&#xff0c;从顶部内侧到内容的最外部分。当内容不超出盒子范围…

项目开发中的自我总结

最近忙的要死,因为新开发了两个项目.现在已经测试完毕了,准备部署到线上了. 然后不能白忙活吧,忙活完也得写点总结和经验吧,以后也有个记录. 1.一个bootstrapjquerylayuilaravel 5.4开发的一个后台系统 比较朴素 2.一个前后端分离的vuelaravel 5.4 开发的商家系统 我只负责后端…

webpack.config.js 参数详解

webpack.config.js文件通常放在项目的根目录中&#xff0c;它本身也是一个标准的Commonjs规范的模块。 var webpack require(webpack); module.exports {entry: [webpack/hot/only-dev-server,./js/app.js],output: {path: ./build,filename: bundle.js},module: {loaders: …

数组黑科技(偏性能方面)未完待更新...

数组去重最优解&#xff1a;Array.prototype.unique function () {var tmp new Map();return this.filter(item > {return !tmp.has(item) && tmp.set(item,1);})}搭配使用 Array.from(foo); // ["f", "o", "o"]let s new Set([f…

控制台添加log4net

1.添加nuget包 log4net 2.app.config配置 <?xml version"1.0" encoding"utf-8"?> <configuration> <configSections><section name"log4net" type"log4net.Config.Log4NetConfigurationSectionHandler, log4net&quo…

记一次vue 普通异步请求微信二进制二维码 乱码 问题解决然后渲染

后端压力大&#xff0c;前端分忧。 /*用微信小程序token拿二维码*/ async fetchMINIQRcode({commit,state},params){var instance axios.create({responseType: blob, //返回数据的格式&#xff0c;可选值为arraybuffer,blob,document,json,text,stream&#xff0c;默认值为js…

vue-cli项目中.postcssrc.js

module.exports {"plugins": {"postcss-import": {}, //用于import导入css文件"postcss-url": {}, //路径引入css文件或node_modules文件"postcss-aspect-ratio-mini": {}, //用来处理元素容器宽高比"postcss-…

本地存储cookie和localStorage区别特点

一、cookie cookie算是比较早的技术&#xff0c;最初是为了记录http的状态&#xff0c;提高访问速度。cookie是服务器"种植"在客户端的key-value形式文本文件。但同时客户端也能操作cookie。特点&#xff1a; 大小&#xff1a;cookie的大小限制在4k。每个域名下cooki…

VUE 中 使用 iview Form组件 enter键防止页面刷新

<Form :label-width"100" inline label-positionleft keydown.native.enter.prevent "()>{}">或者使用官方的 submit.native.prevent转载于:https://www.cnblogs.com/smzd/p/9197915.html

mybatis中#和$区别

在Mybtis中的Mapper映射文件中&#xff0c;sql语句传参有两种方式#{}和${} 一般来说&#xff0c;我们通常使用的是#{}&#xff0c;这里采用的是预编译机制&#xff0c;防止SQL注入&#xff0c;将#{}中的参数转义成字符串&#xff0c;例如&#xff1a; 执行SQL&#xff1a;Selec…

mysql 字段存储多个值 ,判断一个值是否在其中

表C_file,其中有个字段是spile&#xff0c;他存的是字符形式&#xff0c;例如&#xff1a; id spile 1 2,10,11 2 2,3,20,22 3 1,6,8 4 5,6,1,9 select * from C_file where spile LIKE %1% 如果这样查询的话&#xff0c;会查询出ID为1、3、4&#xff0c;但正确的应该是3、…

touchWX 自定义组件以及传值

创建如图文件 index.wxc: <template><view class"wx-test" bindtap"handleTap">{{ msg }}{{dataIndex}}</view> </template> <script>export default {properties: {dataIndex: {type: String,value: default value,}},data…