正则表达式匹配
引例:请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
本题可通过动态规划解决,建立二维数组f,f[i][j]为true表示字符串s中从i到末尾的子序列与模式串p从j到末尾的子序列是匹配的。
在开始之前我们先只看当前位什么情况下匹配。很明显当 s[i] == p[j]或p[j] == '.'时当前位才匹配,不妨把当前位的匹配状态设为match。
接下来就要考虑‘*’的作用了,它表示当前位出现0次或多次,正是它的出现使问题复杂了。不妨分两种情况讨论,分别是有*和无*的情况。
1. 当p[j+1] != '*'时:此时在match为true的基础,f[i+1][j+1]也为true时,f[i][j]才为true。
2. 当p[j+1] == '*'时:正如我们前面所说,它表示p[j]这个字符出现0次或多次,所以我们也分两种情况进行讨论:
2.1 当p[j]出现0次时,也就是说第j项不存在,所以f[i][j]要为true的话,f[i][j+2]必须是true的。(相当于跳过p[j]这个字符,比较下一位,即p[j+2])
2.2 当p[j]出现多次时,此时我们自然会想到底出现多少次才能匹配呢?但是我们用动态规划的思想考虑一下,p[i][j]的结果依赖于p[i+1][j]的结果,所以不妨直接递归这个过程。如下图所示:
这样经过上面的两步,便可以得到结果。
class Solution {
public:
vector<vector<int>> f;
int n,m;
bool isMatch(string s, string p) {
n = s.size();
m = p.size();
f = vector<vector<int>> (n + 1, vector<int>(m + 1, -1));//初始化为-1
return dp(0,0,s,p);
}
bool dp(int x, int y, string& s, string& p){
if(f[x][y] != -1) return f[x][y];
if(y == m){
return f[x][y] = x == n;
}
bool match = x < n && (s[x] == p[y] || p[y] == '.');
bool ans;
if(y + 1 < m && p[y + 1] == '*'){
ans = dp(x, y + 2, s, p) || match && dp(x + 1, y, s, p);
}else{
ans = match && dp(x + 1, y + 1, s, p);
}
return f[x][y] = ans;
}
};