Python·算法·每日一题(2月29日)正则表达式匹配

题目

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

  • ‘.’ 匹配任意单个字符
  • ‘*’ 匹配零个或多个前面的那一个元素
    所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例

示例一

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

示例二

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

示例三

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

思路及算法代码

思路

  • 初始化指针: 首先,通过 i 和 j 分别初始化字符串 s 和正则表达式 p 的指针,它们分别指向各自的最后一个字符。这是因为在匹配过程中,我们希望从字符串和正则表达式的末尾开始向前匹配。

  • 循环匹配: 进入一个循环,直到匹配完成或者判断不匹配为止。循环中的每一步都是根据当前字符以及前面的匹配情况来决定如何移动指针和记录回溯位置。

  • 匹配处理: 在循环中,根据当前字符以及正则表达式的规则进行匹配处理。如果当前字符与正则表达式字符匹配,或者正则表达式字符是通配符 .,则将字符串和正则表达式的指针分别向前移动一位。

  • 特殊情况处理: 当遇到正则表达式中的 * 符号时,表示可能存在重复字符匹配,需要特殊处理。在代码中,我们先检查 * 前是否有字符,如果有,则尝试将 * 匹配 0 个字符,如果可以匹配,则记录当前回溯位置,并将字符串指针向前移动一位。如果不匹配,则直接跳过 * 及其前一个字符,继续向前匹配。

  • 回溯处理: 如果在匹配过程中发现不匹配的情况,且存在回溯位置,则回溯到上一个记录的位置,并尝试其他的匹配方式。在代码中,通过 markj 和 marki 列表来记录回溯位置。

  • 匹配成功: 当正则表达式扫描完毕后,如果字符串也扫描完毕,则表示匹配成功,返回 True;如果字符串未扫描完毕,则返回 False,表示不匹配。

  • 循环结束: 当正则表达式扫描完毕且匹配成功时,循环结束,返回 True;当字符串扫描完毕但正则表达式未扫描完毕时,返回 False,表示不匹配。

代码

class Solution:def isMatch(self, s: str, p: str) -> bool:i = len(s)-1  # 初始化字符串指针,指向最后一个字符j = len(p)-1  # 初始化正则表达式指针,指向最后一个字符markj = []    # 用于记录回溯位置的正则表达式指针marki = []    # 用于记录回溯位置的字符串指针while True:   # 进入无限循环if j < 0: # 如果正则表达式扫描完毕if i >= 0:  # 但字符串未扫描完毕,返回不匹配return Falseelse:   # 字符串也扫描完毕,匹配成功,退出循环break# 如果当前字符匹配或者是通配符'.'if i >= 0 and (p[j] == s[i] or p[j] == '.'):j -= 1  # 向前移动正则表达式指针i -= 1  # 向前移动字符串指针# 如果当前字符是'*'elif p[j] == '*':if j > 0:  # 如果'*'前有字符if i >= 0 and (p[j-1] == s[i] or p[j-1] == '.'):markj.append(j)  # 记录当前位置到回溯列表中marki.append(i)i -= 1  # 向前移动字符串指针,相当于'*'匹配了当前字符else:j -= 2  # 向前移动正则表达式指针,跳过'*'及其前一个字符else:j -= 2  # 向前移动正则表达式指针,跳过'*'及其前一个字符# 如果当前字符不匹配且没有回溯位置else:if len(markj) > 0:  # 如果存在回溯位置j = markj.pop()  # 回溯到上一个记录的位置i = marki.pop()j -= 2  # 向前移动正则表达式指针,跳过'*'及其前一个字符continuereturn False  # 返回不匹配return True  # 循环结束,匹配成功,返回True

复杂度分析

在这个算法中,我们使用了一个 while 循环来扫描字符串和正则表达式。在每次循环中,我们进行了一系列的比较和移动操作,而每个操作都是常数时间复杂度的。因此,总体时间复杂度主要取决于循环的次数。

设字符串的长度为 n,正则表达式的长度为 m。在最坏情况下,每次循环中,我们可能需要向前移动字符串指针和正则表达式指针,直到其中一个指针达到开头。因此,总体时间复杂度为 O(n + m)。

在空间复杂度方面,我们使用了两个列表 markj 和 marki 来记录回溯位置,它们的空间复杂度与回溯次数相关。在最坏情况下,每个字符都可能需要回溯。

回溯的次数受到两个因素的影响:

  • 字符串 s 和正则表达式 p 的长度。回溯的次数取决于较短的字符串。
  • 正则表达式 p 中的 * 符号的数量。每个 * 符号都可能导致一次回溯。

因此空间复杂度为 O(min(n, m))。

综上所述,该算法的时间复杂度为 O(n + m),空间复杂度为 O(min(n, m))。


知识点

回溯算法

回溯算法是一种通过不断尝试可能的解决方案来解决问题的策略。它在解空间中搜索问题的所有可能解,通过逐步向前移动并尝试不同的选择,直到找到解决方案或者确定无解。

回溯算法通常用于解决组合优化问题,例如排列、组合、子集等问题,以及搜索问题的解空间,如图搜索、迷宫求解等。

下面是回溯算法的一般步骤:

  • 选择路径: 从问题的初始状态开始,根据问题的限制和条件,选择一条路径前进。这可以是在问题的解空间中的任何可能的选择。

  • 尝试选择: 将选择应用到当前状态,改变当前状态,并继续向前探索。

  • 检查约束条件: 检查当前状态是否满足问题的约束条件和限制。如果满足,则继续向前探索;否则,回溯到上一个状态,并尝试其他的选择。

  • 终止条件: 当达到问题的终止条件时,即找到一个解决方案,或者搜索完整个解空间后仍未找到解决方案,算法终止。

  • 回溯: 如果当前路径无法找到解决方案,或者达到某个限制条件,算法将回溯到上一个状态,撤销上一次的选择,并尝试其他的选择。

  • 重复搜索: 重复上述步骤,直到找到解决方案或者搜索完整个解空间。

回溯算法的特点是在搜索过程中进行了深度优先遍历,而且不断回溯到之前的状态,尝试其他的可能性。这种方法虽然可以找到解决方案,但在某些情况下可能会需要大量的时间和空间,因此需要合理地设计问题和剪枝策略,以提高算法的效率。

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

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

相关文章

总是 -bash: gomobile: 命令未找到

总是 -bash: gomobile: 命令未找到 问题描述 我的项目是/Users/$user/go/src/abc.com/project 当我尝试在 /Users/GaryChan/go/src/abc.com/project/sdk 并运行: export ANDROID_HOME/Users/$user/Library/Android/sdk/ndk-bundle/gomobile bind -targetandroid abc.com/p…

【Web】Java反序列化之CC6--HashMap版

前文&#xff1a; 【Web】Java反序列化之再看CC1--LazyMap 上面这篇文章提到&#xff0c;只要调用的LazyMap的get方法&#xff0c;就可以最终完成transform的调用。 在高版本下&#xff0c;CC1不再能打通&#xff0c;CC6依然通用&#xff0c;其反序列化入口不再是Annotation…

Leetcode : 215. 数组中的第 K 个最大元素

给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 思路&#xff1a;最开始排序算法&…

MySQL 存储过程批量插入总结

功能需求背景&#xff1a;今天接到产品经理核心业务表的数据压测功能&#xff0c;让我向核心业务表插入百万级的业务量数据&#xff0c;我首先想到的办法就是存储过程实现数据的批量 。 由于无法提供核心业务表&#xff0c;本文仅仅提供我刚刚自己创建的表bds_base_user 表做相…

2.28 进程间的通信 管道 and信号

1.进程间的通信: 1.管道 2.信号 3.消息队列 4.共享内存 5.信号灯 6.套接字 1.管道: 1.无名管道 无名管道只能用于具有亲缘关系的进程间通信 pipe int pipe(int pipefd[2]); 功能: 创建一个无名管道 参数: …

解决vue3按注册名动态渲染组件在setup中无效的问题

在setup语法糖中&#xff0c;按注册名动态渲染组件无效&#xff1a; <template><component :is"cpnName" /> </template> <script setup>import QuesTypeContent from ./QuesTypeContent.vue;const cpnName QuesTypeContent; </script&…

nginx 反向代理 与缓存功能

一 理论说明 &#xff08;一&#xff09;反向代理简介 反向代理&#xff1a;reverse proxy&#xff0c;指的是代理外网用户的请求到内部的指定的服务器&#xff0c;并将数据返回给用户的一种方式&#xff0c;这是用的比较多的一种方式。 即 代理服务机 Nginx 除了可以在企…

算法——滑动窗口之最大连续1的个数、将x减到0的最小操作数、水果成篮

3.最大连续1的个数 题目:. - 力扣&#xff08;LeetCode&#xff09; 题目要求的是给定一个二进制数组 nums 和一个整数 k&#xff0c;如果可以翻转最多 k 个 0 &#xff0c;则返回 数组中连续 1 的最大个数 。 按照题目正面去做,还要替换0,很麻烦 反正我们最后要求的是最长…

YOLOv8改进 | 独家创新篇 | 结合SOTA思想利用双主干网络改进YOLOv8(全网独家创新,最重磅的更新)

一、本文介绍 本文给大家带来的改进机制是结合目前SOTAYOLOv9的思想利用双主干网络来改进YOLOv8(本专栏目前发布以来改进最大的内容,同时本文内容为我个人一手整理全网独家首发 | 就连V9官方不支持的模型宽度和深度修改我都均已提供,本文内容支持YOLOv8全系列模型从n到x均可…

刷题笔记 洛谷 P1162 填涂颜色

思路来自 大佬 hat.openai.com/c/9c30032e-5fb9-4677-8c15-9ea6530dc6db 题目链接 P1162 填涂颜色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路 搜索 首先 在外面围上一圈0开始搜素 因为题目说将封闭区域内的0变成2 我们可以在外面进行搜索 把外面所有可以搜索…

Nginx----高性能的WEB服务端(四)

一、http 协议反向代理 1、反向代理&#xff1a;缓存功能 ​ proxy_cache zone_name | off; 默认off #指明调用的缓存&#xff0c;或关闭缓存机制;Context:http, server, location #zone_name 表示缓存的名称.需要由proxy_cache_path事先定义proxy_cache_key string; #缓存中…

【Redis】深入理解 Redis 常用数据类型源码及底层实现(5.详解List数据结构)

本文是深入理解 Redis 常用数据类型源码及底层实现系列的第5篇&#xff5e;前4篇可移步(&#xffe3;∇&#xffe3;)/ 【Redis】深入理解 Redis 常用数据类型源码及底层实现&#xff08;1.结构与源码概述&#xff09;-CSDN博客 【Redis】深入理解 Redis 常用数据类型源码及底…

BeautifulSoup+xpath+re+css简单复习+新的scrapy的学习

1.BeautifulSoupsoup BeautifulSoup(html,html.parser)all_icosoup.find(class_"DivTable") 2.xpath trs resp.xpath("//tbody[idcpdata]/tr") hong tr.xpath("./td[classchartball01 or classchartball20]/text()").extract() 这个意思是找…

基于RabbitMQ的RPC通信

基于RabbitMQ的RPC通信 版本信息操作步骤搭建RabbitMQ(默认用户名:guest 密码:guest )服务端实现(srv.py)客户端实现(client.py)性能测试(4919 qps) 当需要调用局域网中的服务时,可以用frp进行穿透,也可以在公网搭建RabbitMQ服务器做消息中转,本文演示了这个步骤。 版本信息 …

文件拖放到窗体事件

网上的实现1 实现结果 具体实现代码&#xff1a;注意需要使能允许拖拽 public partial class Form1 : Form {public Form1(){InitializeComponent();this.AllowDrop true; //允许拖拽}private void Form1_DragEnter(object sender, DragEventArgs e){this.Text DateTime.No…

一键安装|卸载 mysql 8.2.0 shell脚本

场景&#xff1a;为了在无网、外网 mysql 安装方便&#xff0c;这里分享一个自己编写得 shell脚本 这里以当前最新版 mysql 8.2.0&#xff1b;centos-7 二进制包下载&#xff1a; 下载地址 mysql_install.sh #!/bin/bash # 解压安装包 tar -xf mysql-8.2.0-linux-glibc2.17-x8…

GO语言学习笔记(与Java的比较学习)(三)

函数 按值传递&#xff08;call by value&#xff09; 按引用传递&#xff08;call by reference&#xff09; Go 默认使用按值传递来传递参数&#xff0c;也就是传递参数的副本。函数接收参数副本之后&#xff0c;在使用变量的过程中可能对副本的值进行更改&#xff0c;但不…

TC3xx SMU、PMIC和Tranceiver的功能安全闭环

目录 1.TLF35584安全状态输出响应对象 1.1 响应ERR 收集到的错误信号 1.2 响应监控功能引发的ROT 1.3 响应看门狗引发的错误 1.4 环境过温引发的错误状态 1.5 为什么设计SSx&#xff1f; 2. 安全状态输出给谁 3.小结 在之前文章里&#xff0c;我们简述了TC3xx SMU如何…

npm install常见错误的完整指南

目录 1. ERR! Error: EACCES2. ERR! ENOENT3. ERR! network timeout4. ERR! Maximum call stack size exceeded5. ERR! Failed at the xxxxxx install script6. ERR! code EINTEGRITY7. ERR! Please try running this command again as root/Administrator8. ERR! code ELIFECY…

尚硅谷(SpringCloudAlibaba微服务分布式)学习代码Eureka部分

1.项目结构 2.cloud2024 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.a…