LeetCode - 解題筆記 - 10- Regular Expression Matching

支錦銘發表於2020-12-19

Regular Expression Matching

Solution 1

【官方題解】看到體面想到了非常複雜的星號匹配規則直接懵逼了……以為是狀態機,所以想到了DP,但是沒有對問題建模清楚。官方的題解很有分析意義,因此這裡直接使用這個題解。定義最優子結構ans[i][j]表示輸入的第i+1個字元及以後與正則的第j+1個字元及以後的匹配結果。更新狀態按照正則匹配規則更新即可。邊界條件上有三個地方:如果正則為空,輸入只有為空時才匹配正確;二者的末尾空值匹配結果為dp[S][P] = true,作為初始值用於迭代;輸入末尾空值dp[S][P-1]不能直接置true,因為如果正則末尾恰為星號需要額外進行判斷,需要在迭代時考慮正則與輸入末尾空值的比較。

這麼一看這個並不是很複雜,aaaaa*a*的匹配我想複雜了,動態規劃可以將5種匹配方案都涵蓋進去。

  • 時間複雜度: O ( S P ) O(SP) O(SP) S S S P P P分別是輸入和正則的長度
  • 空間複雜度: O ( S P ) O(SP) O(SP) S S S P P P分別是輸入和正則的長度
class Solution {
public:
    bool isMatch(string s, string p) {
        // 邊界判定:空空為true
        if (p.size() == 0) {
            return s.size() == 0;
        }
        
        vector<vector<bool>> ans(s.size() + 1, vector<bool>(p.size() + 1, false));
        ans[s.size()][p.size()] = true;
        
        for (int i = s.size(); i >= 0; i--) {
            // 這裡考察末尾空的情況主要是應對正則最後一個是*的情形
            for (int j = p.size() - 1; j >= 0; j--) {
                // 當前位置匹配:字母相同或者字母萬用字元
                // 如果正則末尾是*,直接和輸入末尾空比較為負,否則會進入二者的末尾空比較,true
                bool current = (i < s.size()) && (s.at(i) == p.at(j) || p.at(j) == '.');
                
                // 星號判斷
                if (j + 1 < p.size() && p.at(j + 1) == '*') {
                    // 0次,直接跳過p中的這兩個字元;任意多次,當前匹配正確並向後檢視s
                    ans[i][j] = (ans[i][j + 2] || current && ans[i + 1][j]);
                } else {
                    ans[i][j] = current && ans[i + 1][j + 1];
                }
                // cout << i << j << ans[i][j] << endl;
            }
        }
        
        return ans[0][0];
    }
};

Solution 2

Solution 1的Python實現

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        if len(p) == 0:
            return (len(s) == 0)
        
        ans = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
        
        # print(ans)
        ans[len(s)][len(p)] = True
        # print(len(s), len(p), ans)
        
        for i in range(len(s), -1, -1):
            for j in range(len(p) - 1, -1, -1):
                current = (i < len(s)) and ((s[i] == p[j]) or (p[j] == '.'))
                
                if j + 1 < len(p) and p[j + 1] == '*':
                    ans[i][j] = (ans[i][j + 2]) or (current and ans[i + 1][j])
                else:
                    ans[i][j] = current and ans[i + 1][j + 1]
        
                # print(i, j, ans[i][j], ans)
        return ans[0][0]

相關文章