Regular Expression Matching
题目描述
输入一个字符串s和一个匹配模式p,返回两者是否匹配。匹配规则如下
.可以替代任何字符
*可以重复其之前的字符任何次数(包括0次)
特别的 .*表示任意次数的. 而不是某个确定字符的任意次数
分析
终于刷到一个DP题了,以前做题的时候总是觉得DP最难,现在最想遇到DP题,不想写数据结构。
f[i, j]
表示s[:i+1] p[:j+1]
是否匹配,状态转移方程如下:
-
s[i] == p[j] or p[j] == '.'
f[i, j] = f[i-1, j-1]
-
p[j] == '*' and 'a' <= p[j-1] <= 'z'
f[i, j] |= f[k, j-2] until s[k] != p[j-1] (k = i; k >= 0; k--)
-
p[j] == '*' and p[j-1] == '.'
f[i, j] |= f[k, j-2] (k = i; k >= 0; k--)
注意边界,我这边为了处理边界,给每个字符串头部添加了一个#
代码
class Solution {
public:
bool isMatch(string s, string p) {
int len_s = s.size() + 1, len_p = p.size() + 1;
s.insert(0, "#");
p.insert(0, "#");
bool f[21][31] = { false };
f[0][0] = true;
for (int i = 0; i < len_s; i++) {
for (int j = 0; j < len_p; j++) {
if (i + j == 0)
continue;
if (i == 0)
{
if (p[j] >= 'a' && p[j] <= 'z' or p[j] == '.')
f[i][j] = false;
if (j > 1 && p[j] == '*')
f[i][j] = f[i][j - 2];
continue;
}
if (j == 0)
{
f[i][j] = false;
continue;
}
if (p[j] >= 'a' && p[j] <= 'z')
{
if (s[i] == p[j])
f[i][j] = f[i - 1][j - 1];
else
f[i][j] = false;
}
if (p[j] == '.')
f[i][j] = f[i - 1][j - 1];
if (j > 1 && p[j] == '*' && p[j - 1] >= 'a' && p[j - 1] <= 'z')
{
for (int k = i; k >= 0; k--)
{
if (f[k][j - 2])
{
f[i][j] = true;
break;
}
if (s[k] != p[j - 1])
break;
}
}
if (j > 1 && p[j] == '*' && p[j - 1] == '.')
{
for (int k = i; k >= 0; k--)
{
if (f[k][j - 2])
{
f[i][j] = true;
break;
}
}
}
}
}
return f[len_s - 1][len_p - 1];
}
};
思考
总感觉这个匹配规则和标准的正则匹配有点不同,但有人直接用正则匹配的函数好像也能AC,挺神奇的