🌟每日一题|剑指Offer地狱级难题!正则表达式匹配,你能扛住吗?🌟
💡题目描述
《剑指Offer 19. 正则表达式匹配》
请实现一个函数用来匹配包含'.'
和'*'
的正则表达式。模式中的字符'.'
表示任意一个字符,'*'
表示它前面的字符可以出现任意次(含0次)。例如,字符串"aaa"
与模式"a.a"
或"ab*ac*a"
匹配,但与"aa.a"
或"ab*a"
不匹配。
难度:⭐⭐⭐⭐⭐(地狱级动态规划)
🚨核心提示
1️⃣ 动态规划是本题的最优解方向
2️⃣ 注意'*'
的特殊性:它必须和前面的字符组合使用
3️⃣ 分情况讨论:当前字符是否匹配?下一个字符是否是'*'
?
🧠解题思路拆解
Step 1:定义状态
dp[i][j]
表示字符串s
的前i
个字符与模式p
的前j
个字符是否匹配。
Step 2:初始化
dp[0][0] = true
:空字符串匹配空模式- 处理模式中
'*'
开头的情况:如a*b*c*
可能匹配空字符串
Step 3:状态转移
-
Case 1:
p[j-1] != '*'
当前字符必须匹配:s[i-1] == p[j-1]
或p[j-1] == '.'
且之前的结果也必须匹配:dp[i][j] = dp[i-1][j-1]
-
Case 2:
p[j-1] == '*'
- 子情况1:
*
匹配0次 → 丢弃x*
组合:dp[i][j] = dp[i][j-2]
- 子情况2:
*
匹配≥1次 → 必须满足当前字符匹配,且字符串前移:dp[i][j] = dp[i-1][j]
- 子情况1:
Step 4:处理边界
- 当
s
为空时,模式必须类似a*b*
的形式才能匹配
🚀代码实现(Java)
class Solution {
public boolean isMatch(String s, String p) {
int m = s.length(), n = p.length();
boolean[][] dp = new boolean[m+1][n+1];
dp[0][0] = true;
// 初始化第一行(s为空字符串的情况)
for(int j=2; j<=n; j+=2) {
if(p.charAt(j-1) == '*' && dp[0][j-2]) {
dp[0][j] = true;
}
}
for(int i=1; i<=m; i++) {
for(int j=1; j<=n; j++) {
char sc = s.charAt(i-1);
char pc = p.charAt(j-1);
if(pc != '*') {
if(sc == pc || pc == '.') {
dp[i][j] = dp[i-1][j-1];
}
} else {
// 处理 '*' 的情况
if(j >= 2) {
// 选择匹配0次 或 匹配多次
dp[i][j] = dp[i][j-2] ||
((sc == p.charAt(j-2) || p.charAt(j-2) == '.') && dp[i-1][j]);
}
}
}
}
return dp[m][n];
}
}
🧠测试用例
- Case 1:
s="aa", p="a*"
→true
- Case 2:
s="ab", p=".*"
→true
(.*
匹配任意字符串) - Case 3:
s="", p="a*b*c*"
→true
📌灵魂拷问
-
Q:为什么不用递归而用动态规划?
A:递归时间复杂度爆炸(指数级),动态规划将复杂度优化到O(mn) -
Q:如何处理
a*
匹配零次的情况?
A:直接跳过这两个字符(即dp[i][j] = dp[i][j-2]
)
💬 评论区互动
“你在面试中遇到过这道题吗?花了多久AC的?欢迎晒出你的解题经历!” 🔥
文章评论