1. 程式人生 > >【重點 遞迴 動態規劃 正則表示式匹配】LeetCode 10. Regular Expression Matching

【重點 遞迴 動態規劃 正則表示式匹配】LeetCode 10. Regular Expression Matching

LeetCode 10. Regular Expression Matching

Solution1:遞迴

程式碼中的註釋寫的不是太清楚,加一點:
一、當模式中的第二個字元不是“*”時:
1、如果字串第一個字元和模式中的第一個字元相匹配,那麼字串和模式都後移一個字元,然後匹配剩餘的。
2、如果字串第一個字元和模式中的第一個字元相不匹配,直接返回false。
二、當模式中的第二個字元是“*”時:
如果字串第一個字元跟模式第一個字元不匹配,則模式後移2個字元,繼續匹配。如果字串第一個字元跟模式第一個字元匹配,可以有3種匹配方式:
1、x*匹配0個字元。模式後移2字元,相當於x*被忽略;(一開始忘了即使當前字元匹配,也存在忽略掉的情況!!!)
2、x*匹配1個字元。字串後移1字元,模式後移2字元;
3、x*匹配多於1個字元。字串後移1字元,模式不變,即繼續匹配字元下一位,因為*可以匹配多位;
注意:情況2可以被情況1和情況3包含。執行一次情況3,再執行一次情況1,就相當於情況2。

class Solution {
public:
    bool isMatch(string s, string p) {
        if (p.empty()) return s.empty();
        if (p.size() == 1) {
            return (s.size() == 1 && (s[0] == p[0] || p[0] == '.'));
        }
        //if the next character in pattern is not '*'
        if (p[1] != '*') {
            //第一個條件沒有判斷s.size()是否為0,看似有溢位的可能
//實際上此處另有玄妙,見下面分解! if (s[0] == p[0] || (!s.empty() && p[0] == '.')) return isMatch(s.substr(1), p.substr(1)); else return false; } //if the next character is '*' else { if (s[0] == p[0] || (!s.empty
() && p[0] == '.')) return isMatch(s, p.substr(2)) || isMatch(s.substr(1), p); //剛開始一直不懂為何要返回match(str, pattern+2)的值,原因在於'*'可以匹配0個字元 //即使是當前字元匹配,也存在匹配0個字元的情況 else return isMatch(s, p.substr(2)); } } };

關於C++中空string

C++中的string和C語言的字串有一點很像,那就是當string物件其實也是以字元’\0’結尾的,這跟C語言中一致。
這也就解釋了下面這段程式不會報錯的原因。

string s = ""; // s是空串
cout << (int)s[0] << endl;
//程式輸出為0,也就是'\0'字元

Solution2:動態規劃

動態規劃還是稍微有點難理解啊,不過至少要牢記遞迴的方法!
我們也可以用DP來解,定義一個二維的DP陣列,其中dp[i][j]表示s[0,i)和p[0,j)是否match,然後有下面三種情況(下面部分摘自這個帖子):
1. P[i][j] = P[i - 1][j - 1], if p[j - 1] != ‘*’ && (s[i - 1] == p[j - 1] || p[j - 1] == ‘.’);
2. P[i][j] = P[i][j - 2], if p[j - 1] == ‘*’ and the pattern repeats for 0 times;
3. P[i][j] = P[i - 1][j] && (s[i - 1] == p[j - 2] || p[j - 2] == ‘.’), if p[j - 1] == ‘*’ and the pattern repeats for at least 1 times.

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size(), n = p.size();
        vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
        dp[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (j > 1 && p[j - 1] == '*') {
                    dp[i][j] = dp[i][j - 2] 
                    || (i > 0 && (s[i - 1] == p[j - 2] 
                    || p[j - 2] == '.') && dp[i - 1][j]);
                } else {
                    dp[i][j] = i > 0 && dp[i - 1][j - 1] 
                    && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
                }
            }
        }
        return dp[m][n];
    }
};