文章目录

  • 题目
  • 思路
    • 转移方程
    • 特征
    • 再探 i 和 j
  • 代码

题目

请实现一个函数用来匹配包含 .* 的正则表达式。模式中的字符 . 表示任意一个字符,而 * 表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 aaa 与模式 a.aab*ac*a 匹配,但与 aa.aab*a 均不匹配。

来源:力扣(LeetCode)


思路

再一次膜拜大佬 作者:jyd
本文基于大佬的思路做自己的细节解析。

其实动规的难点一直在于“找规律”。(恐怕这也是所有算法题的难点,哈哈)

本题其实就是在考察程序员思考问题的全面性。

转移方程

先建立这道题的转移方程:

f[i][j] 代表 s 的前 i 个和 p 的前 j 个能否匹配。

当正则表达式中为 正常字符. 时,问题是很好解决的:

f[i][j]=f[i−1][j−1]

前 i 个 s前 j 个 p 是否匹配还要看 前 i-1 个 s前 j-1 个 p 是否匹配。

难点就在于是 字符 + * 时该怎么处理:

分为将字符看成 出现0次(也就是不看这两位)和 出现多次(看这个组合):

  • 不看:直接砍掉正则串的后面两个, f[i][j] = f[i][j-2]
  • 看:正则串不动,主串前移一个,f[i][j] = f[i-1][j]

上面两点,大部分题解已经说的很明白了,但其实又很抽象。我们不妨用例子来看一下:

  • 第一种比较好理解 —— f[i][j] = f[i][j-2]

s=abcd
p=abcde*

将主串的最后一位视为 i(a),正则串最后一位视为 j(*)。显而易见两个字符串是完全匹配的。只需要 * 前面的 e(j-1) 出现0次就可(正则串里面的 d 就是 j-2)。

  • 第二种理解起来可能有点抽象 —— f[i][j] = f[i-1][j]

s=abccc
p=abc*

此时 i为cj为*,因为 *前面的字符 可以 出现多次,也就是出现1次的递归操作。因此此时我们做的操作就是:

  • 已经知道了 ij(也就是*前的字符) ,那么再试着看看 i-1 还是不是 j

也就是原本相互匹配的字符我们不看了(都做-1操作),ij 彼此是匹配的,理应再看 i-1j-1,但是我们想要 j 多出现几次,因此 j-1 的操作没有执行。这就是下图中,jyd大佬所说的 p[j-2]多出现1次

图中总说 s[i-1] p[j-1] 为什么不是直接用 s[i] p[j] 呢?这个问题讲完初始化dp数组首行我们再细说。

特征

弄懂了主要的验证是否匹配的操作,接下来我们需要弄懂一些特例:

首先明晰一点:正则串和主串都是可以为空串的。

  • 空主串空正则是匹配的。
  • 非空串空正则必不匹配。
  • 空主串非空正则,不能直接判定匹配与否。
  • 非空串非空正则,那肯定是需要计算的了。

我们可以根据上面的特征,来初始化dp二维数组。

行代表s,列代表p,dp[0][j] 代表s为空,dp[i][0]代表p为空。

第四点其实就是我们的转移方程。因此我们来详解一下第三点:

s= '' '' 时,p=a*b*c*p=ab* 前者可以做到和空主串完美匹配,后者却不行。因此我们可以得出以下规律:


因此可以得到初始化dp首行的代码(首列无需做多余更改,空正则除了匹配空主串,其余皆不匹配):

// 初始化dp首行
dp[0][0] = 1;
for(size_t i = 2; i < cols; i += 2){dp[0][i] = dp[0][i-2] && p[i-1] =='*';
}

再探 i 和 j

我读完大佬写的题解的时候其实还是很懵懂的,真正豁然开朗是看了大佬的图解。大佬做图解一直有一手的~

下面结合图解来讲一下我们遗留的问题,dp[i][j] 和与之相对应的 s[i-1] p[j-1]

我们借用一下大佬的图来看一下:

我们会发现,前面提到:

  • 第一行,也就是下标为0的那行,代表 s 为空串
  • 第一列,也就是下标为0的那列,代表 p 为空串

我们是从第二行(下标为1的行)和第二列(下标为1的列)开始保存 s 和 p 的非空部分的

因此,举个具体的例子:dp[1][1]其逻辑含义是,保存的值表示 前1个s前1个p 是否匹配。在物理上代表 s[0]p[0] 组成的点。因此我们也就不难理解大佬图解中频繁出现的 dp[i][j]s[i-1] p[j-1] 之间的关系了。


代码

class Solution {public:bool isMatch(string s, string p) {int rows = s.size()+1;int cols = p.size()+1;vector<vector<int>> dp(rows, vector<int>(cols, 0));// 初始化dp首行dp[0][0] = 1;for(size_t i = 2; i < cols; i += 2){dp[0][i] = dp[0][i-2] && p[i-1] =='*';}// 动规for(size_t i = 1; i < rows; i++){for(size_t j = 1; j < cols; j++){if(p[j-1] != '*'){if(dp[i-1][j-1] && (s[i-1]==p[j-1] || p[j-1] == '.')){dp[i][j] = 1;}}else{if(dp[i][j-2] || (dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.'))){dp[i][j] = 1;}}}}return dp[rows-1][cols-1];}
};

正则表达式匹配(动规)相关推荐

  1. re2正则表达式匹配引擎的c接口版本cre2的中文使用手册

    前言 re2 官方地址: https://github.com/google/re2 cre2 官方地址: https://github.com/marcomaggi/cre2 1 基本类型定义 不透 ...

  2. Oracle正则表达式匹配中文的问题

    查资料知道中文Unicode范围是\u4e00 - \u9fa5 可是自己用来正则表达式匹配中文总是用不了Unicode.最简单举例: select regexp_replace('abc秋歌def' ...

  3. python3 正则表达式 嵌套表格_在Python中使用正则表达式匹配嵌套结构

    unutbu.. 14 编辑: falsetru的嵌套解析器,我稍微修改为接受任意正则表达式模式来指定分隔符和项目分隔符,比我原来的re.Scanner解决方案更快更简单: import re def ...

  4. 剑指offer:面试题19. 正则表达式匹配

    题目:正则表达式匹配 请实现一个函数用来匹配包含'. '和'*'的正则表达式.模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次).在本题中,匹配是指字符串的所有字符匹 ...

  5. 使用正则表达式匹配HTML 下各种title标签

    http://www.oschina.net/question/195686_46313 <title>标题</title> <title> 标题 </tit ...

  6. 刻意练习:LeetCode实战 -- Task18. 正则表达式匹配

    背景 本篇图文是LSGO软件技术团队组织的 第二期基础算法(Leetcode)刻意练习训练营 的打卡任务.本期训练营采用分类别练习的模式,即选择了五个知识点(数组.链表.字符串.树.贪心算法),每个知 ...

  7. 通配符?子字符串匹配主字符串次数_突破LeetCode,拿BAT大厂offer之《正则表达式匹配》(动态规划)...

    导读:算法哥前面分享了一个<通配符匹配>,有粉丝留言,算法哥你再讲讲leetcode上另一道<正则表达式匹配>,正则表达式匹配这道题是前面通配符匹配的加强版,大家一起来学习吧! ...

  8. Java算法练习——正则表达式匹配

    题目链接 题目描述 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配. '.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要 ...

  9. 正则表达式匹配换行符

    正则表达式匹配换行符 一开始没有发现html文档中有很多\n,结果用模式 <table[^>]>.*</table> 得到的table间的数据不正确,根据百度百科,可以看 ...

最新文章

  1. 如何高效地爬取链家的房源信息(四)
  2. php lvs,LVS(四)LVS集群DR模式
  3. 非标自动化企业前十名_非标设备的现状
  4. http详解 请求报文格式和响应报文格式
  5. c++实现超声回波包络检测_超声波物位计的选用
  6. SpringBoot - yml与properties配置文件及bean赋值
  7. c#使用SHA256算法实现对文件的加密和解密
  8. javatodo框架中怎么配置路由
  9. 如何终止运行中的线程
  10. GlobalMapper20提取点云LAS文件当中的投影信息
  11. 税务会计实务【15】
  12. 靠谱的社交app有哪些
  13. 无线网络优化(家用无线网)
  14. c51语言访问绝对地址的方法,51单片机绝对地址访问的两种方法
  15. notifier_chain 内核通知链的学习与使用
  16. iis php 500 内部服务器错误,服务器_iis的http 500内部服务器错误的解决,iis的http 500内部服务器错误是 - phpStudy...
  17. 区块链大繁荣背后:我们需要引入「预言机」| 专访DOS团队
  18. 安卓修改电池容量教程_安卓手机端修改电池电量图标的教程
  19. 你不知道的颠覆式创新者
  20. 无法打开模块文件“C:\Users\fkg\AppData\Local\Temp\.NETFramework,Version=v4.5.AssemblyAttributes.vb”系统找不到指定文件

热门文章

  1. python私有属性怎么定义_Python中定义私有属性的方法是()。
  2. java ldap 分页_具有从属引用的 LDAP 分页查询未正确处理
  3. 编译mediastreamer2/ffmpeg/linphone(x86平台)
  4. java fx 建立窗体,3花式窗体与JavaFX CSS
  5. 计算机组装与维护实验指导,计算机组装与维护实验指导书.pdf
  6. arcgis选出点规定范围的面
  7. 【转】聊聊Linux操作系统中的显示管理器及如何更换
  8. python可以开发驱动吗_Python机器学习实践:测试驱动的开发方法
  9. java内存分配和垃圾回收,Java内存分配与垃圾回收
  10. 【Python学习】win10+Anaconda3环境,安装phthon第三方库Jieba