C++实现带有通配符的字符串匹配 _ 递归与动态规划思路【源码】

轻浩酱_8997

轻浩酱_8997

2026-04-13

588人浏览

原创

ismatch递归易栈溢出因“”导致指数级分支,如“a”配“aaa”时每个“”尝试多长度匹配;应加记忆化、提前剪枝、避免裸或逻辑,并用dpi表示s[0..i-1]与p[0..j-1]匹配,注意“*”转移需按行正向填表。

c++实现带有通配符的字符串匹配 _ 递归与动态规划思路【源码】

为什么 isMatch 递归写法在遇到 "*" 时容易栈溢出

通配符匹配里最耗资源的是 "*",它能匹配任意长度子串(包括空串),递归分支呈指数爆炸。比如模式 "********a" 配字符串 "aaa",每个 "*" 都会尝试“匹配 0 个、1 个、2 个……”直到失败回溯,实际调用深度远超字符串长度。

实操建议:

  • 加记忆化——用 memo[i][j] 记录 s[i:] 和 p[j:] 是否已算过,避免重复递归
  • 提前剪枝:若 p[j] 是 "*",先递归跳过它(即 "*" 匹配空串),再递归让它吃掉 s[i] 后继续——不要用 for 循环枚举吃几个字符
  • 别直接写 return isMatch(s, p, i+1, j) || isMatch(s, p, i, j+1) 这类裸或逻辑,C++ 短路求值虽存在,但编译器未必优化掉冗余调用;显式拆成 if 判断更可控

dp[i][j] 状态定义和初始化怎么不踩边界坑

动态规划里最容易错的是状态含义和数组下标偏移。推荐统一用 dp[i][j] 表示 s[0..i-1](前 i 个字符)能否被 p[0..j-1](前 j 个字符)匹配,这样空字符串对应 i=0 或 j=0,边界自然清晰。

关键初始化细节:

  • dp[0][0] = true:空串匹配空模式
  • dp[0][j](j > 0):只有当 p[j-1] 是 "*" 且 dp[0][j-1] 为 true 时才可能为 true——因为 "*" 是唯一能匹配空串的非空模式
  • dp[i][0](i > 0)恒为 false:非空串无法被空模式匹配

错误常见于把 dp[i][j] 定义成 “以 i、j 结尾”,导致初始化混乱或循环越界。

处理 "?" 和 "*" 的转移逻辑差异在哪

"?" 和 "*" 看似都是通配,但状态转移完全不同:"?" 是确定性跳转,"*" 是不确定性分叉。

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载

具体到 dp[i][j] 更新:

  • 若 p[j-1] == '?':必须消耗一个字符,dp[i][j] = dp[i-1][j-1]
  • 若 p[j-1] == '*':两种选择——“不吃字符”(dp[i][j-1])或“吃一个并继续留着它”(dp[i-1][j]),即 dp[i][j] = dp[i][j-1] || dp[i-1][j]
  • 若 p[j-1] 是普通字符:仅当 s[i-1] == p[j-1] 且 dp[i-1][j-1] 为 true 时成立

注意:"*" 的转移依赖 dp[i-1][j],所以内层循环必须按行(i)顺序填表,不能按列;否则 dp[i-1][j] 还没算就用了。

空间优化时为什么只能滚动一维而不能只用两个变量

从二维 dp[i][j] 压到一维 dp[j] 是可行的,但必须保留整行,不能只记上一行和当前行的几个值。原因在于 "*" 的转移要同时访问 dp[j-1](左边)和 dp[j](上方,即上一轮 i-1 时的值)。

实操要点:

  • 用单数组 vector<bool> dp(m+1)</bool>,其中 m = p.length()
  • 外层遍历 i(s 的位置),内层从 j = 1 到 m 正向遍历——保证更新 dp[j] 时,dp[j-1] 是本轮新值(对应 dp[i][j-1]),而旧的 dp[j] 还是上轮值(对应 dp[i-1][j])
  • 不能反向遍历,否则 dp[j] 被覆盖后,dp[j+1] 就拿不到正确的上轮值了

真正难的不是写出状态转移,而是理解 "*" 引入的“左+上”联合依赖如何约束遍历方向——这点漏掉,优化后结果必错。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.03

1618

5

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

2404

5

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

2023.10.24

5884

49

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2023.11.24

5149

6

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

2024.03.22

6854

16

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

2024.04.29

9494

11

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

2025.07.29

4819

17

c++字符串相关教程
c++字符串相关教程

本专题整合了c++字符串相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.07

5087

13

常用字符串方法大全
常用字符串方法大全

常用字符串方法大全

2025.08.08

2628

14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习