經典題目——正則表達式匹配

正則表達式匹配

引例:請實現一個函數用來匹配包括'.'和'*'的正則表達式。模式中的字符'.'表示任意一個字符,而'*'表示它前面的字符可以出現任意次(含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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章