经典题目——正则表达式匹配

正则表达式匹配

引例:请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含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]的结果,所以不妨直接递归这个过程。如下图所示:
图1 字符串匹配过程图
由于p[j+1]是*,需要从s序列中找最多能匹配多少位,如图所示,最多匹配到第5位,当匹配到第6位时,match为false,所以p[6][0]就是false,进而p[5][0]、p[4][0]、p[3][0]……一直到当前的p[i][j]都是false,于是得到本层结果。

这样经过上面的两步,便可以得到结果。
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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章