当前位置: 首页 > news >正文

LeetCode 10:正则表达式匹配

LeetCode 10:正则表达式匹配

在这里插入图片描述

问题本质:精准匹配规则

实现支持 .(匹配任意单个字符)和 *(匹配前一个字符0次或多次)的正则表达式,要求完全匹配字符串 s,而非部分匹配。

核心思路:动态规划(DP)

通过二维 DP 表记录状态:dp[i][j] 表示 s 的前 i 个字符p 的前 j 个字符是否匹配。

算法步骤详解

步骤 1:状态定义

创建二维数组 dp,维度为 (m+1) × (n+1)m = s.length()n = p.length()):

  • dp[i][j]s 的前 i 个字符(s[0..i-1])与 p 的前 j 个字符(p[0..j-1])是否匹配。
步骤 2:初始化边界
  • 空字符串匹配dp[0][0] = true(空 s 匹配空 p)。
  • 处理 p 前导的 *:若 pa*b* 形式开头,空 s 也可匹配。例如:
    • p[j-1] == '*' 时,dp[0][j] = dp[0][j-2](忽略 p[j-2]p[j-1],即 * 匹配0次前一个字符)。
步骤 3:状态转移(核心逻辑)

遍历 is 的前 i 个字符)和 jp 的前 j 个字符),分两种情况:

情况 1:p[j-1] ≠ '*'(普通字符或 .
  • s[i-1]p[j-1] 匹配(s[i-1] == p[j-1]p[j-1] == '.'),且 s 的前 i-1 个字符与 p 的前 j-1 个字符匹配dp[i-1][j-1] == true),则 dp[i][j] = true
情况 2:p[j-1] == '*'(匹配前一个字符0次或多次)

* 修饰 p[j-2],分两种子情况:

  • 子情况 1:* 匹配0次:忽略 p[j-2]p[j-1],则 dp[i][j] = dp[i][j-2]
  • 子情况 2:* 匹配至少1次:需满足:
    1. s[i-1]p[j-2] 匹配(s[i-1] == p[j-2]p[j-2] == '.');
    2. s 的前 i-1 个字符与 p 的前 j 个字符匹配dp[i-1][j] == true,因为 * 可延续匹配)。
      此时 dp[i][j] |= dp[i-1][j](“或”操作,继承子情况1的结果)。

完整代码(Java)

class Solution {public boolean isMatch(String s, String p) {int m = s.length();int n = p.length();boolean[][] dp = new boolean[m + 1][n + 1];dp[0][0] = true; // 空字符串匹配空正则// 初始化:处理p中前导的*(空s匹配p的情况)for (int j = 2; j <= n; j++) {if (p.charAt(j - 1) == '*') {dp[0][j] = dp[0][j - 2];}}// 填充DP表for (int i = 0; i <= m; i++) {for (int j = 1; j <= n; j++) {if (p.charAt(j - 1) != '*') {// 情况1:普通字符或.,需i>0且当前字符匹配,且前i-1和j-1匹配if (i > 0 && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.')) {dp[i][j] = dp[i - 1][j - 1];}} else {// 情况2:*,分匹配0次和至少1次// 子情况1:匹配0次,直接继承j-2的状态dp[i][j] = dp[i][j - 2];// 子情况2:匹配至少1次,需i>0且当前字符匹配,继承i-1的状态if (i > 0 && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.')) {dp[i][j] |= dp[i - 1][j];}}}}return dp[m][n];}
}

关键细节解析

  1. 索引处理s[i-1]p[j-1] 对应字符串的第 ij 个字符(数组从0开始)。
  2. * 的灵活性:通过“匹配0次”和“匹配至少1次”的逻辑,覆盖所有可能的重复情况。
  3. 初始化优化:提前处理 p 中前导 * 的情况,确保空字符串的匹配性。

复杂度分析

  • 时间复杂度O(m×n)mn 分别是 sp 的长度,双重循环遍历所有状态。
  • 空间复杂度O(m×n),存储二维 DP 表。

示例验证

  • 示例 2s="aa", p="a*"):
    • dp[2][2]p[1]='*',匹配0次时 dp[2][0]=false;匹配至少1次时,s[1]='a' == p[0]='a',且 dp[1][2]=truei=1 时已匹配),故 dp[2][2]=true
  • 示例 3s="ab", p=".*"):
    • p[1]='*' 修饰 .,匹配0次时 dp[2][0]=false;匹配至少1次时,s[1]='b'. 匹配,且 dp[1][2]=truei=1s[0]='a' 匹配 .),故 dp[2][2]=true

该方案通过动态规划精准建模匹配状态,高效处理 * 的复杂逻辑,确保了正则表达式匹配的正确性与性能。

http://www.dtcms.com/a/296540.html

相关文章:

  • MyBatis-Plus--PageHelper 与 MyBatis-Plus 分页插件
  • SAP全自动化工具开发:Excel自动上传与邮件通知系统
  • Flutter之Widget体系与布局原理
  • 汉字转拼音
  • Kiro AI是如何帮我实现发布 harpoon 项目
  • 如何使用 php-vulnerability-hunter
  • 中国网专访百胜软件董事长兼CEO黄飞:中台助力新时代下零售行业的探索
  • go下载包
  • go语言基础教程:【1】基础语法:变量
  • Verilog 提取信号的上升沿或者下降沿
  • Python中常用标准库(时间库、随机库、正则表达式)
  • shell 正则表达式
  • Golang 语言中的指针介绍
  • 高版本Android跨应用广播通信实例
  • 40、鸿蒙Harmony Next开发:UI场景化-组件截图(ComponentSnapshot)
  • C++第一节课入门
  • Qt 元对象系统(Meta-Object System)解析
  • 前端安全问题怎么解决
  • 企业资产管理智能化:IT运维如何借力数字化管理提效避坑?
  • 配置DNS服务的正反向解析
  • 详解FreeRTOS开发过程(六)-- 队列
  • ESP32- 项目应用1 智能手表之更新时间 #3
  • Linux系统常用命令
  • 浅析飞算JavaAI “撤回需求” 功能:让需求管理更灵活
  • 【C++】类和对象(中)
  • 【三桥君】Windows系统如何临时关闭“Windows安全中心实时保护”?解析Win10和Win11关闭方法
  • C++中std::string和std::string_view使用详解和示例
  • Lua(字符串)
  • 生成式人工智能展望报告-欧盟-03-经济影响
  • pyautogui 置信度问题