Leetcode算法系列| 10. 正则表达式匹配

目录

  • 1.题目
  • 2.题解
    • C# 解法一:分段匹配法
    • C# 解法二:回溯法
    • C# 解法三:动态规划

1.题目

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
1.‘.’ 匹配任意单个字符
2.‘.’ 匹配任意单个字符
所谓匹配,是要涵盖 整个 字符串 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 的小写字母,以及字符 . 和 *。
    • 保证每次出现字符 * 时,前面都匹配到有效的字符

2.题解

  • 映入脑海的第一个想法是将数字转换为字符串,并检查字符串是否为回文。但是,这需要额外的非常量空间来创建问题描述中所不允许的字符串。
  • 第二个想法是将数字本身反转,然后将反转后的数字与原始数字进行比较,如果它们是相同的,那么这个数字就是回文。
  • 但是,如果反转后的数字大于 int.MAX\text{int.MAX}int.MAX,我们将遇到整数溢出问题。
  • 按照第二个想法,为了避免数字反转可能导致的溢出问题,为什么不考虑只反转 int\text{int}int 数字的一半?毕竟,如果该数字是回文,其后半部分反转后应该与原始数字的前半部分相同。
    例如,输入 1221,我们可以将数字 “1221” 的后半部分从 “21” 反转为 “12”,并将其与前半部分 “12” 进行比较,因为二者相同,我们得知数字 1221 是回文。

C# 解法一:分段匹配法

  • 根据星号的位置将p切割为多个 尾星串 与 至多一个 无星串,然后从p头到p尾求M值。求解p的某段的M值时,需要根据上一段的M值来依次求解;若上一段M不包含任何值,则匹配失败。若p从头到尾走完了, 则判断最终的M中是否包含了 s.length-1 这个值, 若包含了,则s与p是匹配的。
public class Solution {public bool IsMatch(string s, string p){List<int> M1 = new List<int>() { -1 };while (p.Length > 0 && M1.Count > 0){List<int> M2 = new List<int>() { };int pStarIndex = p.IndexOf("*");foreach (int m1 in M1){string sRight = s.Substring(m1 + 1);if (pStarIndex == -1){var result = IsMatchNoStar(sRight, p);//无星说明是p的最后一组,若匹配成功则s与p匹配,直接返回true;否则直接continueif (result) return true;continue;}//有星,需要 找到 p[0,starIndex] 与 s 的匹配点//先判断p[0,starIndex-2]的字符与s的一一对应 int mNow = -1;bool isMatchBeforeStar = true;for (int i = 0; i < pStarIndex - 1; i++){if (i >= sRight.Length){isMatchBeforeStar = false; break;}mNow = i;if (!IsMatchChar(sRight[i], p[i])){isMatchBeforeStar = false; break;}}if (!isMatchBeforeStar) continue;//因为*可以表示0个,所以先将mNow添加到 匹配点集M2.Add(mNow + (m1 + 1));mNow++;//再看p[startIndex-1] 与 s的匹配点,找出所有的匹配点 while (mNow < sRight.Length && IsMatchChar(sRight[mNow], p[pStarIndex - 1])){M2.Add(mNow + (m1 + 1));mNow++;}}//将startIndex以及之前的串给舍弃,留下startIndex+1以及之后的串p = p.Substring(pStarIndex + 1);//更新M1 M1 = M2;}return M1.Contains(s.Length - 1);}public bool IsMatchNoStar(string s, string p){if (s.Length != p.Length){return false;}for (int i = 0; i < s.Length; i++){if (!IsMatchChar(s[i], p[i])){return false;}}return true;}public bool IsMatchChar(char sc, char pc){return ((pc == '.') || (sc == pc));}
}

可以牺牲部分可读性 来提高效率, 优化后的代码:

public class Solution {public bool IsMatch(string s, string p){List<int> M1 = new List<int>() { -1 };List<int> M2 = new List<int>() { };int pStart = 0;while (p.Length - pStart > 0 && M1.Count > 0){int pStarIndex = p.IndexOf("*", pStart);foreach (int m1 in M1){int sStart = m1 + 1;int sRightLen = s.Length - sStart;if (pStarIndex == -1){//IsMatchNoStarvar result = true;if (s.Length - sStart != p.Length - pStart) result = false;else{for (int i = 0; i < s.Length - sStart; i++){if (!((s[sStart + i] == p[pStart + i]) || (p[pStart + i] == '.'))){result = false;break;}}}if (result) return true;continue;}int mNow = -1;bool isMatchBeforeStar = true;int pLenBeforeStar = pStarIndex - pStart - 1;for (int i = 0; i < pLenBeforeStar; i++){if (i >= sRightLen){isMatchBeforeStar = false; break;}mNow = i;if (!((s[sStart + i] == p[pStart + i]) || (p[pStart + i] == '.'))){isMatchBeforeStar = false; break;}}if (!isMatchBeforeStar) continue;M2.Add(sStart + mNow++);int pCharIndexBeforeStar = pStarIndex - 1;while (mNow < sRightLen && ((s[sStart + mNow] == p[pCharIndexBeforeStar]) || (p[pCharIndexBeforeStar] == '.')))M2.Add(sStart + mNow++);}pStart = pStarIndex + 1;var tempMs = M1; M1 = M2; M2 = tempMs;M2.Clear();}return M1.Contains(s.Length - 1);}
}

1

  • 时间复杂度:O( pLen * sLen^2 )
    • 最坏的情况下,s全是同一个字母,p是同一个字母加星号,如 s=“aaaaaaa”,p= “aaa*” 。此时外层while以及找星的位置可以看作pLen,内层foreach每次都是对s的遍历,执行次数为sLen,再内层的 for与while加起来 又是对s的遍历,复杂度大概为 O( pLen * sLen^2 )
  • 空间复杂度:O( pLen * sLen )
    • 我第二层循环里面存在常数数量的变量定义,故为 O(pLen*sLen)

C# 解法二:回溯法

  • 回溯法解体的思路与分段匹配法类似,但使用递归后,只需要非常少的代码量。

  • 以p为主串,从左向右去匹配s,匹配成功的部分都去掉,也就是说 若最终s与p都变成了空串,则匹配成功。

  • 代码结构也很简单,首先是出口,然后是递归分支。

  • 出口EXIT:p变成空串时,若s也变成了空串,则匹配成功,否则匹配失败。

  • 分支A:p[1]为星号,直接去掉p的前两位,并递归。如 s=“b”,p=“a*b”.

  • 分支B:p[1]为星号时,若s第一位与p第一位匹配,去掉s第一位 , 并递归,如 “s=aab”,p=“ab"。否则匹配失败,如 s=“bba”,p="ab”.

  • 分支C:p[1]不为星号时,若s与p第一位匹配成功, 则都去掉第一位,并递归,如 s=“aab”,p=“aab*”. 否则匹配失败,如 s=“bab”, p=“aab*” .

  • 其中,当p[1]为星号时,分支A与分支B是【或】的关系,只要有一条成功,则匹配成功; 当p[1]不为星号时,就走C。

public class Solution {public bool IsMatch(string s, string p){//出口,EXITif (string.IsNullOrEmpty(p)) return string.IsNullOrEmpty(s); //Exitbool first_match = (   !string.IsNullOrEmpty(s) &&(p[0] == s[0] || p[0] == '.'));if (p.Length >= 2 && p[1] == '*')return (IsMatch(s, p.Substring(2)) ||       // A(first_match && IsMatch(s.Substring(1), p))); //Belse return first_match && IsMatch(s.Substring(1), p.Substring(1)); // C}
}

可以使用下标指针来代替SubString,从而明显的提高代码效率。 优化后的代码:

public class Solution {public bool IsMatch(string s, string p) { return IsMatch1(s, 0, p, 0); }public bool IsMatch1(string s, int sStart, string p, int pStart){if (pStart == p.Length) return sStart == s.Length; //Exitbool first_match = (sStart < s.Length &&(p[pStart] == s[sStart] || p[pStart] == '.'));if (p.Length - pStart >= 2 && p[pStart + 1] == '*')return (IsMatch1(s, sStart, p, pStart + 2) ||       // A(first_match && IsMatch1(s, sStart + 1, p, pStart))); //Belsereturn first_match && IsMatch1(s, sStart + 1, p, pStart + 1); // C}
}

2

  • 时间复杂度:O( (sLen+pLen) 2^(sLen+pLen/2) )*
  • 空间复杂度:O( (sLen+pLen) 2^(sLen+pLen/2) )*

C# 解法三:动态规划

public class Solution {public bool IsMatch(string s, string p){bool[,] dp = new bool[s.Length + 1, p.Length + 1];dp[s.Length, p.Length] = true;for (int i = s.Length; i >= 0; i--){for (int j = p.Length - 1; j >= 0; j--){bool first_match = (i < s.Length && (p[j] == s[i] || p[j] == '.'));if (j + 1 < p.Length && p[j + 1] == '*'){dp[i, j] = dp[i, j + 2]    //A|| first_match && dp[i + 1, j]; //B}else{dp[i, j] = first_match && dp[i + 1, j + 1]; // C}}}return dp[0, 0];}
}

3

  • 时间复杂度:O(sLen*pLen)
    • 最table中每个值会被计算一次,不会重复计算,而每个格子的计算时间可认为是O(1),所以总时间复杂度为O(sLen*pLen)
  • 空间复杂度:O(sLen*pLen)
    • able空间复杂度为 O(sLen*pLen).

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

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

相关文章

网络运行状况监控工具

网络运行状况是网络在其操作和环境约束范围内按预期运行的能力&#xff0c;但是&#xff0c;随着云和人工智能等技术的出现&#xff0c;网络变得越来越复杂&#xff0c;维护其 IT 基础设施是一项越来越繁琐的任务。为了确保网络可靠性&#xff0c;组织需要了解每个端点的运行状…

Halcon颜色通道的处理decompose3/image_to_channels/channels _to _image

Halcon颜色通道的处理 文章目录 Halcon颜色通道的处理一. 图像的通道二. 访问通道1.访问通道2.获取通道的数量 三. 通道分离与合并1. decompose3算子2. image_to_channels 算子3. compose3算子4. channels_to_image算子 四. 处理RGB信息 由于彩色图像通常包含不止一个通道&…

拍照就能建模!手机就能访问! 这个技术正成为宣传新手段!

随着人工智能技术的不断进步&#xff0c;现在可以通过拍摄照片结合AI技术来实现3D模型生成。这种技术的出现&#xff0c; 不仅能更加方便快捷地创建3D模型&#xff0c;而且还能真实复原现实中物件的质感、纹理等。同时&#xff0c;极大地降低了各行业对3D技术的应用门槛&#x…

中科院1区TOP,Elsevier出版社,均1-2个月录用!检索超稳!

【SciencePub学术】本期&#xff0c;小编给大家推荐的是一本Elsevier旗下、工程技术领域、影响因子为6.0的中科院1区TOP。其详情如下&#xff1a; 期刊简介 TRIBOLOGY INTERNATIONAL ISSN&#xff1a;0301-679X E-ISSN&#xff1a;1879-2464 IF&#xff08;2022&#x…

ES6+ 面试常问题

一、let const var 的区别 1. var&#xff1a; 没有块级作用域的概念&#xff0c;有函数作用域和全局作用域的概念全局作用域性下创建变量会被挂在到 windows 上存在变量提升同一作用域下&#xff0c;可以重复赋值创建未初始化&#xff0c;值为 undefined 2. let&#xff1a…

最新AI系统ChatGPT网站H5系统源码,支持AI绘画,GPT语音对话+ChatFile文档对话总结+DALL-E3文生图

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

经典文献阅读之--OccNeRF(基于神经辐射场的自监督多相机占用预测)

0. 简介 作为基于视觉感知的基本任务&#xff0c;3D占据预测重建了周围环境的3D结构。它为自动驾驶规划和导航提供了详细信息。然而&#xff0c;大多数现有方法严重依赖于激光雷达点云来生成占据地面真实性&#xff0c;而这在基于视觉的系统中是不可用的。之前我们介绍了《经典…

【 ATU NXP-SBC 系列 】FS26XX GUI_OTP烧录与模拟操作

1. 概述 FS26XX 为了其安全性需求&#xff0c;针对重要暂存器的配置&#xff0c;使用 one time program 的功能&#xff0c;避免不小心修改重要暂存器&#xff0c;导致发生重大意外&#xff0c;使系统丧失功能安全性。FS26XX 也可以让使用者先测试 OTP 后的结果功能&#xff0…

微信小程序开发系列-03全局配置中的“window”和“tabBar”

微信小程序开发系列目录 《微信小程序开发系列-01创建一个最小的小程序项目》《微信小程序开发系列-02注册小程序》《微信小程序开发系列-03全局配置中的“window”和“tabBar”》《微信小程序开发系列-04获取用户图像和昵称》《微信小程序开发系列-05登录小程序》《微信小程序…

C# 如何使用?、? 和 ??的区别和使用案例

目录 ? 运算符 使用案例 ?? 运算符 使用案例 总结 在 C# 中&#xff0c;? 和 ?? 运算符在处理 null 值时起着不同的作用&#xff0c;并且具有特定的使用场景。 ? 运算符 ? 运算符&#xff0c;也称为空条件运算符&#xff0c;在 C# 6.0 及更高版本中引入。它允许…

08-React路由(Router 6版本)

Router5和Router6的变化 部分标签产生了变化&#xff0c;之前的标签都有了替&#xff08;主要集中在Route匹配上&#xff09;&#xff0c;所以这里先回顾一下Router5&#xff0c;同时引出Router6的一些新特性 其次&#xff0c;React官方在推出Router6之后&#xff0c;就明确推…

OpenCV-Python(9):图像基础操作

目录 学习目标 获取图像像素并修改像素值 获取图像属性 图像ROI 拆分及合并图像通道 图像边缘扩充 学习目标 获取像素值并修改获取图像的属性(信息)图像的ROI获取图像通道拆分及合并图像扩边 获取图像像素并修改像素值 几乎所有这些操作与Numpy 的关系要比与OpenCV 的…

【电商项目实战】MD5登录加密及JSR303自定义注解

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《电商项目实战》。&#x1f3af;&#x1f3af; &am…

飞书文档如何转markdown

飞书文档如何转markdown 实现效果实现步骤其他方法 实现效果 导出的结果挂在这了 https://thinkasany.github.io/docs/#/ 实现步骤 以https://upyun.feishu.cn/docx/KERsd1DpioPb1xxye9VcuXbhnBC这篇文章为例 使用工具 https://github.com/Wsine/feishu2md&#xff0c;提供了…

案例-旋转的太极图案(HTML+CSS)

使用css的动画变换效果完成“ 旋转太极“。 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>*{margin: 0;padding: 0;background-color: antiquewhite;}.tj{width: 0;height: 300px;/* border…

AWTK 开源串口屏开发(4) - 采用数据

AWTK 开源串口屏开发 - 数据采集 1. 功能 数据采集是一个常用的功能&#xff0c;MCU 定时采集数据&#xff08;如环保设备定时采样空气中的污染物&#xff09;&#xff0c;并发送采样数据到串口屏&#xff0c;串口屏可以显示采样数据&#xff0c;也可以对采样数据进行管理&am…

68.乐理基础-打拍子-大附点与变体

上一节内容&#xff1a;66.乐理基础-打拍子-小切分-CSDN博客&#xff0c;只所以没有67因为67可以不用知道&#xff0c;67节内容在&#xff1a;※-打拍子&#xff08;8&#xff09;-一拍内的变体1-乐理教程-腾讯课堂 (qq.com) 大附点&#xff1a;大附点这个名字不是通用的&…

基于element-ui table组件的二次封装

文章目录 配置数据基础分析封装 el-table-column使用插槽强化结语 相信 element-ui 大家都有所耳闻&#xff0c;table 也是老朋友了&#xff0c;不过在使用它的时候大家是怎么使用的呢&#xff1f;是直接在官网上cv使用吗&#xff1f;这种方式&#xff0c;我相信写起来会有点小…

【教学类-43-02】20231226 九宫格数独2.0(n=9)(ChatGPT AI对话大师生成 回溯算法)

作品展示&#xff1a; 背景需求&#xff1a; 大4班20号说&#xff1a;我不会做这种&#xff08;九宫格&#xff09;&#xff0c;我做的是小格子的&#xff0c; 他把手工纸翻过来&#xff0c;在反面自己画了矩阵格子。向我展示&#xff1a; “我会做这种&#xff01;” 原来他…

OCR在审核应用落地

本文字数&#xff1a;6686字 预计阅读时间&#xff1a;35分钟 01 背景 1、业务背景 在传统视频审核场景中&#xff0c;审核人员需要对进审视频中的文字内容进行逐一审核&#xff0c;避免在文字上出现敏感词、违禁词或者广告等相关词汇。这种人工审核费时费力&#xff0c;并且由…