leetcode刷题(剑指offer) 10.正则表达式匹配

10.正则表达式匹配

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.''*' 的正则表达式匹配。

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

提示:

  • 1 <= s.length <= 20
  • 1 <= p.length <= 20
  • s 只包含从 a-z 的小写字母。
  • p 只包含从 a-z 的小写字母,以及字符 .*
  • 保证每次出现字符 * 时,前面都匹配到有效的字符

解法

本题是实现一个简易的正则表达式匹配,对于本题而言,有两种方案。

  1. 动态规划
  2. 有限状态机

正则表达式的引擎则是由有限状态机实现的,由于博主还没搞懂怎么使用有限状态机来解,所以这篇文章主讲如何使用 动态规划来解。

首先确定转移方程。

我们把dp[i][j]定义为字符串s的前i位能否和字符规律p的前j位字符匹配上。在动态规划中,我们已知的可以使用来求解dp[i][j]的变量有dp[i][j]之前的所有dp值,s[i], p[j]等。

下面可以思考一下会存在哪些情况。在本题中主要存在三种字符串: 普通的字符串, *****, .

先考虑简单的。

  • 普通字符串:

    • p[j] == s[i]的时候,说明最新遍历到的字符串s字符规律p之间的最新一位是可以匹配上的,那么就只要看之前能不能匹配上就可以了,也就是dp[i][j] = d[i - 1][j - 1]
    • p[j] != s[i]的时候,说明最新的一位就匹配不上,那么先前能不能匹配上就已经不重要了,最后一定匹配不上直接dp[i][j] = false
  • 遇到了**.**:

    • 当遇到点的时候,说明,最新的s和p的最新一位是可以匹配上的,这种情况就和遇上普通字符串时候的p[j] == s[i]情况一致,只要看之前有没有匹配上就可以了。
  • 遇到了*****: 这也是这题最难的一点*可以匹配任意多个*前面的字符,会分为两种情况

    • *前面的字符能和s[i]不能匹配的时候,此时dp[i][j]就是由dp[i][j - 2]的值决定,因为*也可以表示匹配0个*前面的字符,前面的字符匹配不上,直接扔了,然后再看看能不能匹配上。
    • *前面的字符能和s[i]能匹配的时候,dp[i][j]就是由dp[i][j - 2]dp[i - 1][j]的值来决定,因为当*能和s[i]匹配上的时候也分为两种情况,第一种如下:s = "bb", p = "bbb*"当i = 2, j = 4的时候,直接忽略掉p中的b*。p可以和s匹配上。第二种情况如下:s = "bbbb", p = "bbb*",使用*匹配多个b,p也可以和s匹配上。

先举个案例,s = "aab", p = "c*a*b"。下一步直接打表。

黄色和红色部分均为初始化,橙色部分为后续需要填写的。

初始化部分:当p和s都为空的时候一定是可以匹配上的;当p为空,且s不为空的时候,他们一定是无法匹配的;当s为空,且p不为空的时候,只有*能匹配。

初始化实现代码如下:

// dp[i][j]: 表示s的前i位字符串能否匹配p的前j位字符串
boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
// 初始化0时候的数据
dp[0][0] = true;
// 初始化没有s,只有p的时候的数据
for (int i = 1; i <= p.length(); i++) {if (p.charAt(i - 1) == '*') {if (i - 2 < 0) {dp[0][i] = false;}else {dp[0][i] = dp[0][i - 2];}}else {dp[0][i] = false;}
}

dp赋值的橙色部分,则按照上述的三种字符串的逻辑来填充。

代码如下:

package com.offer;import java.util.HashMap;
import java.util.Map;public class _10正则表达式匹配 {public static void main(String[] args) {String s = "aab";String p = "c*a*b";System.out.println(isMatch(s, p));}public static boolean isMatch(String s, String p) {// dp[i][j]: 表示s的前i位字符串能否匹配p的前j位字符串boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];// 初始化0时候的数据dp[0][0] = true;// 初始化没有s,只有p的时候的数据for (int i = 1; i <= p.length(); i++) {if (p.charAt(i - 1) == '*') {if (i - 2 < 0) {dp[0][i] = false;}else {dp[0][i] = dp[0][i - 2];}}else {dp[0][i] = false;}}// 如果s长度为0,且p长度不为0,不能确定能否匹配成功// 如果p长度为0,但是s长度不为0,那么一定匹配失败,所以这第一列可以直接全部初始化成falsefor (int i = 1; i <= s.length(); i++) {for (int j = 1; j <= p.length(); j++) {if (p.charAt(j - 1) == '*') {if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.') {dp[i][j] = dp[i][Math.max(j - 2, 0)] || dp[i - 1][j];}else {// 去掉匹配字符a*再试试dp[i][j] = dp[i][Math.max(j - 2, 0)];}}else {if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') {dp[i][j] = dp[i - 1][j - 1];}else {dp[i][j] = false;}}}}printfDp(dp);return dp[s.length()][p.length()];}private static void printfDp(boolean[][] dp) {for (int i = 0; i < dp.length; i++) {for (int j = 0; j < dp[i].length; j++) {System.out.print(dp[i][j] + "\t");}System.out.println();}}}

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

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

相关文章

Linus Torvalds的20个事实

Linus Torvalds 是 Linux 操作系统的创造者&#xff0c;至今还在维护内核。本文是他的自传《Just for fun》的简短摘录&#xff0c;关于他个人的20个事实&#xff0c;比如他的老婆是他的学生。 Brief: Some known, some lesser known – here are 20 facts about the Linus Tor…

外汇天眼:Cryptodfmeta与Aden Markets──网恋对象热心带投资,鼓吹加码冻账拒出金

随着整个人类社会进入数字时代&#xff0c;我们愈来愈仰赖网络科技的便利性&#xff0c;由于远端工作逐渐成为趋势&#xff0c;就连社交与人际互动也开始云端化。 与此同时&#xff0c;诈骗集团也在各大社交平台申请假账号并寻找下手目标&#xff0c;并且诱骗人使用虚假的投资平…

JSON概述以及使用

1&#xff0c;JSON 1.1 概述 概念&#xff1a;JavaScript Object Notation。JavaScript 对象表示法. 如下是 JavaScript 对象的定义格式&#xff1a; {name:"zhangsan",age:23,city:"北京" } 接下来我们再看看 JSON 的格式&#xff1a; {"name&…

C++文件操作(1)

C文件操作 1.文本的写入及读取文本文件写入文本文件读取 2.二进制文件的写入及读取二进制文件写入二进制文件读取 3.小结 C也有处理文件的能力&#xff0c;其功能实现依赖文件流。文件流是C中用来处理文件输入输出的一种流类。文件流可以用于从文件中读取数据或将数据写入到文件…

uni-app小程序自定义导航栏

最近在开发一个uni-app小程序&#xff0c;用到了自定义导航栏&#xff0c;在这里记录一下实现过程&#xff1a; page.json 在对应页面路由的style中设置入"navigationStyle": "custom"取消原生导航栏&#xff0c;自定义导航栏 {"path": "…

【ARM Trace32(劳特巴赫) 使用介绍 6.1 -- 外设寄存器查看与修改】

请阅读【Trace32 ARM 专栏导读】 文章目录 外设寄存器查看与修改寄存器值修改外设寄存器查看与修改 外设寄存器的查看与修改,离不开TRACE32的外设文件(*.per),per文件一般存在于TRACE32的安装根目录下。 一般情况下,在调试时,TRACE32会根据当前选择的芯片名自动选择合适的…

正则表达式(RE)

什么是正则表达式 正则表达式&#xff0c;又称规则表达式&#xff08;Regular Expression&#xff09;。正则表达式通常被用来检索、替换那些符合某个规则的文本 正则表达式的作用 验证数据的有效性替换文本内容从字符串中提取子字符串 匹配单个字符 字符功能.匹配任意1个…

P1596 [USACO10OCT] Lake Counting S Flood Fill算法(洪水填充算法)

文章目录 题目链接题目描述解题思路算法原理实现方法复杂度分析 代码实现总结 题目链接 链接: P1596 [USACO10OCT] Lake Counting S 题目描述 解题思路 本题我在acwing和洛谷上都看到了 做这道题首先要了解一下Flood Fill 算法&#xff08;洪水填充算法&#xff09; 作为一个…

数据库MySQL查询设计||给定四个关联表,其定义和数据加载如下:-- 学生表 Student-- 选课表 SC

SQL查询设计 给定四个关联表&#xff0c;其定义和数据加载如下&#xff1a; -- 学生表 Student create table Student(Sno varchar(6), Sname varchar(10), Sdate datetime, Ssex varchar(10)); insert into Student values(01 , 赵雷 , 1999-01-01 , 男); insert into St…

重发布

一&#xff1a;作用 在两种路由协议之间&#xff0c;或者一个协议的不同进程之间&#xff0c;借助ASBR &#xff08;同时工作在两种协议或 者协 议的不同进程中&#xff09;学习到两个网络的路由信息&#xff0c;并且通过重发布进行路由共享&#xff0c;最终实现全网可 达。…

tarojs View多行文本无法换行问题解决

问题&#xff1a;未换行 code&#xff1a; 解决&#xff1a; 加上换行属性的css就好了 white-space: break-spaces;

(十一)springboot实战——springboot3下关于WebFlux项目的一些常用功能整合

前言 本节内容主要是对webflux项目一些常用功能的介绍&#xff0c;例如系统集成swagger接口文档&#xff0c;方便接口测试以及前后端项目联调测试&#xff1b;使用actuator完成系统各种指标的监控功能&#xff1b;系统使用logback日志框架完成项目日志的收集&#xff1b;使用过…