剑指offer52_正则表达式匹配_题解
正则表达式匹配
题目描述
请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
示例1
输入
"aaa","a*a"
返回值
true
分析
方案一:递归
算法思想:
- 递归函数功能:\(match(s,p)\)表示 \(p\) 是否可以匹配 \(s\)
- 递归终止条件:当 \(p\) 为空时,若 \(s\) 也为空,表明匹配正确;若 \(s\) 不为空,则表明不能正确匹配
- 递归逻辑:
- 如果 \(p[1]==*\),表明 \(p[0]\) 对应的字符可以重复 \(0\) 次或者多次
- 重复 \(0\) 次,则继续匹配 \(s[0...m]\) 和 \(p[2...n]\)
- 重复多次,继续匹配 \(s[1...m]\) 和 \(p[0...n]\)
- 如果 \(p[0]==s[0]\) 且 \(p[0]≠*\),则匹配 \(s[1...m]\) 和 \(p[1...n]\)
- 否则返回 \(false\)
- 如果 \(p[1]==*\),表明 \(p[0]\) 对应的字符可以重复 \(0\) 次或者多次
代码
/**
1.时间复杂度:小于O(mn)
2.空间复杂度:O(m)、O(n)和递归栈的空间
**/
class Solution
{
public:
bool match(string s, string p)
{
if (p.empty())
return s.empty();
bool first_match = !s.empty() && (s[0] == p[0] || p[0] == '.');
if (p.size() >= 2 && p[1] == '*')
return match(s, p.substr(2)) || (first_match && match(s.substr(1), p));
else
return first_match && match(s.substr(1), p.substr(1));
}
bool match(char *str, char *pattern)
{
string s(str), p(pattern);
return match(s, p);
}
};
方案二:动态规划
算法思想:
代码
/**
1.时间复杂度:O(mn)
m和n分别是字符串s和p的长度。
2.空间复杂度:O(mn)
存储所有状态使用的空间
**/
class Solution
{
public:
bool first_match(string s, string p, int i, int j)
{
return s[i] == p[j] || p[j] == '.';
}
bool match(char *str, char *pattern)
{
string s(str), p(pattern);
int ls = s.size(), lp = p.size();
vector<vector<bool>> dp(ls + 1, vector<bool>(lp + 1));
dp[0][0] = true;
for (int j = 2; j <= lp; j++)
dp[0][j] = (p[j - 1] == '*' && dp[0][j - 2]);
for (int i = 0; i < ls; i++)
{
for (int j = 0; j < lp; j++)
{
if (p[j] == '*')
{
dp[i + 1][j + 1] = dp[i + 1][j - 1] || first_match(s, p, i, j - 1) && dp[i][j + 1];
}
else
{
dp[i + 1][j + 1] = first_match(s, p, i, j) && dp[i][j];
}
}
}
return dp[ls][lp];
}
};