10.正则表达式匹配 (Hard)*
题目描述*
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例*
s = "aab"
p = "c*a*b"
提示*
s 可能为空,且只包含从 a-z 的小写字母。p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
代码*
虽然学过动态规划,但是看到这个题还是有点发怵。跟随带哥的文章学习螺旋上升的算法学习过程。
首先,从普通的字符串比较出发:
bool isMatch(string text, string pattern) {
if(text.length() != pattern.length()) {
return false;
}
for(int i = 0; i < pattern.length(); i++) {
if(pattern[i] != text[i]) {
return false;
}
}
return true;
}
之后我们尝试把这个代码改为递归的形式,正则匹配将基于递归的框架实现。
bool isMatch(string text, string pattern) {
if(pattern.length() == 0) {
return text.length() == 0;
}
bool firstMatch = (text.length() != 0 && text[0] == pattern[0]);
return firstMatch && isMatch(text.substr(1), pattern.substr(1));
}
在这个框架的基础上我们一步步实现正则匹配,首先对于 . 的实现,匹配任意字符:
bool isMatch(string text, string pattern) {
if(pattern.length() == 0) {
return text.length() == 0;
}
bool firstMatch = (text.length() != 0 && (pattern[0] == '.' || pattern[0] == text[0]));
return firstMatch && isMatch(text.substr(1), pattern.substr(1));
}
接下来处理 * 的实现,匹配前一个字符任意次数,包括零次,我们不能确定到底是几次,不过对于递归,我们只需要处理当前的情况:
bool isMatch(string text, string pattern) {
if(pattern.length() == 0) {
return text.length() == 0;
}
bool firstMatch = (text.length() != 0 && (pattern[0] == '.' || pattern[0] == text[0]));
if(pattern.length() >= 2 && pattern[1] == '*') {
// 当前字符后面出现了 *
// 选择匹配零次,即跳过 pattern 的这两个字符
// 选择匹配一次,text 前进一个字符
return isMatch(text, pattern.substr(2)) ||
(firstMatch && isMatch(text.substr(1), pattern));
}else {
return firstMatch && isMatch(text.substr(1), pattern.substr(1));
}
}
到这其实我们就实现了正则匹配的功能。我们可以通过动态规划的思路来优化这个问题,避免子字符串重复划分。
dp[i + 1][j + 1] 表示 text 的前 i 个是否能被 pattern 的前 j 个匹配。
class Solution {
public:
bool isMatch(string text, string pattern) {
int lenText = text.length(), lenPattern = pattern.length();
vector<vector<bool>> dp(lenText + 1, vector<bool>(lenPattern + 1, false));
dp[0][0] = true;
// 初始化 为了匹配空串
for(int i = 1; i < lenPattern; i++) {
if(pattern[i] == '*' && dp[0][i - 1]) {
dp[0][i + 1] = true;
}
}
for(int i = 0; i < lenText; i++) {
for(int j = 0; j < lenPattern; j++) {
if(text[i] == pattern[j] || pattern[j] == '.') {
dp[i + 1][j + 1] = dp[i][j];
}else if(pattern[j] == '*') {
if(pattern[j - 1] == '.' || text[i] == pattern[j - 1]) {
dp[i + 1][j + 1] = dp[i][j + 1] || dp[i + 1][j - 1];
}else {
dp[i + 1][j + 1] = dp[i + 1][j - 1];
}
}
}
}
return dp[lenText][lenPattern];
}
};
最后更新: July 23, 2022