乘风破浪: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,一经查实,立即删除!

相关文章

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…

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

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

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

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

项目开发中的自我总结

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

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

数组去重最优解&#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…

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…

vue 初始框架

VueJs讲解初始框架 一、启动项目 第一步&#xff1a;cmd进入项目文件里&#xff0c;运行npm run dev 启动项目 这里说明启动端口号是8080 第二步&#xff1a;往页面输入&#xff1a;localhost:8080 二、解析渲染步骤 先看整体框架样式和index.html&#xff1a; 从上面我…

Country Road Aizu - 2104

题目链接&#xff1a; https://vjudge.net/problem/Aizu-2104 题解&#xff1a; 咋说啊&#xff0c;一言难尽&#xff0c;花了半小时写出来的&#xff0c;卡了十分钟才恍然大明白是排序。 具体就是让每个村子都通上电&#xff0c;变压器在的村子&#xff0c;与变压器连线点线长…

IdentityServer4【QuickStart】之使用asp.net core Identity

使用asp.net core Identity IdentityServer灵活的设计中有一部分是可以将你的用户和他们的数据保存到数据库中的。如果你以一个新的用户数据库开始&#xff0c;那么&#xff0c;asp.net core Identity是一个选择。这个示例演示了如何在IdentityServer中使用asp.net core Ientit…

vue demo1

1.开发工具 试过sublime&#xff0c;现在转战vscode&#xff0c;觉得很顺手&#xff0c;总之啥工具习惯就好。 vscode用着不错的插件&#xff0c;推荐安装。 2.项目目录介绍 vue-cli生成的项目目录有点多&#xff0c;初看有点懵&#xff0c;梳理一下会好很多。 ├── ind…

CentOS下防御或减轻DDoS攻击方法(转)

查看攻击IP 首先使用以下代码&#xff0c;找出攻击者IP netstat -ntu | awk {print $5} | cut -d: -f1 | sort | uniq -c | sort -n 将会得出类似如下的结果&#xff1a; 1 114.226.9.132 1 174.129.237.157 1 58.60.118.142 1 Address 1 servers) 2 118.26.131.78 3 123.125.1…

vscode - 添加背景图片

首先&#xff0c;CtrlShiftP安装backround &#xff0c; 而后重启vscode会有默认的背景图片 修改背景图&#xff0c;可自定义三张 具体请看gif图 最开始时&#xff0c;发现png根本不是全透明&#xff0c;用ps处理了一下&#xff08;下列所有操作均字母组合&#xff09; 1.1 Ctr…

关于Vue.use()详解

问题 相信很多人在用Vue使用别人的组件时&#xff0c;会用到 Vue.use() 。例如&#xff1a;Vue.use(VueRouter)、Vue.use(MintUI)。但是用 axios时&#xff0c;就不需要用 Vue.use(axios)&#xff0c;就能直接使用。那这是为什么呐&#xff1f; 答案 因为 axios 没有 install。…

分布式工具的一次小升级⏫

前言 之前在做 秒杀架构实践 时有提到对 distributed-redis-tool 的一次小升级&#xff0c;但是没有细说。 其实主要原因是&#xff1a; 秒杀时我做压测&#xff1a;由于集成了这个限流组件&#xff0c;并发又比较大&#xff0c;所以导致连接、断开 Redis 非常频繁。 最终导致获…

浅谈vue $mount()

Vue 的$mount()为手动挂载&#xff0c;在项目中可用于延时挂载&#xff08;例如在挂载之前要进行一些其他操作、判断等&#xff09;&#xff0c;之后要手动挂载上。new Vue时&#xff0c;el和$mount并没有本质上的不同。 具体见代码&#xff1a; 顺便附上vue渲染机制流程图&a…

论一个程序员的自我修养-从一张图片说起

故事起源 本来今天想写.NET Core实战之CMS系统第十五篇文章的。哈&#xff0c;奈何今天在新生命人脉群里面看到石头哥分享的一张图片&#xff0c;然后大家就议论了起来&#xff0c;不过我看的很懵逼&#xff0c;这图什么意思啊&#xff1f;当一个朋友讲述了这个图片背后的故事的…

c/c++ 继承与多态 文本查询的小例子(非智能指针版本)

问题&#xff1a;在上一篇继承与多态 文本查询的小例子&#xff08;智能指针版本&#xff09;在Query类里使用的是智能指针&#xff0c;只把智能指针换成普通的指针&#xff0c;并不添加拷贝构造方法&#xff0c;会发生什么呢&#xff1f; 执行时&#xff0c;代码崩掉。 分析下…

HTML渲染过程详解

由于本人对http协议以及dns对url的解析问题并不了解&#xff0c;所以这里之探讨url请求加载到浏览器端时&#xff0c;浏览器对html的解析到呈现过程&#xff0c;后来经过几位道友分享&#xff0c;整理了一下url解析的过程&#xff0c;如下&#xff1a; 用户输入url地址&#x…

vue之router-view组件的使用

开发的时候有时候会遇到一种情况&#xff0c;比如 &#xff1a;点击这个链接跳转到其他组件的情况&#xff0c;通常会跳转到新的页面&#xff0c;蛋是&#xff0c;我们不想跳转到新页面&#xff0c;只在当前页面切换着显示&#xff0c;那么就要涉及到路由的嵌套了&#xff0c;也…