【線性 dp】A010_LC_正則表達式匹配(分類討論)

一、Problem

給你一個字符串 s 和一個字符規律 p,請你來實現一個支持 ‘.’ 和 ‘*’ 的正則表達式匹配。

‘.’ 匹配任意單個字符
‘*’ 匹配零個或多個前面的那一個元素
所謂匹配,是要涵蓋 整個 字符串 s的,而不是部分字符串。

說明:

s 可能爲空,且只包含從 a-z 的小寫字母。
p 可能爲空,且只包含從 a-z 的小寫字母,以及字符 . 和 *。

輸入:
s = "aa"
p = "a"
輸出: false
解釋: "a" 無法匹配 "aa" 整個字符串。

輸入:
s = "aab"
p = "c*a*b"
輸出: true
解釋: 因爲 '*' 表示零個或多個,這裏 'c' 爲 0 個, 'a' 被重複一次。因此可以匹配字符串 "aab"。

二、Solution

方法一:dp

  • 定義狀態
    • f[i][j]f[i][j] 表示 s 的前 ii 個字符能否被 p 的前 jj 個字符匹配
  • 思考初始化:
    • f[0][0]=truef[0][0] = true,表示空串與空串可匹配
    • f[0][j]=f[0][j2] && p[i1]=f[0][j] = f[0][j-2]\ \&\&\ p[i-1] = * 表示字符串 p 的前 jj 個字符只有當 p[j2]p[j-2] 爲空串,且 s[j1]s[j-1]* 時纔可以匹配。
  • 思考狀態轉移方程:注:i1&&j1(i \geqslant 1 \&\& j \geqslant 1)
    • 如果 s[i]=p[j]  p[j]=.s[i] = p[j]\ ||\ p[j] = . 則有 f[i][j]=f[i1][j1]f[i][j] = f[i-1][j-1],否則 —>
    • 如果 p[j]=p[j] = *,此時的 * 號有兩種作用:
      • 清空:有 f[i][j]=f[i][j2]f[i][j] = f[i][j-2],即將字符串 p 的第 j1j-1 個字符清走,比如 (ab, abc*),就將字母 c 清走
      • 補全:如果 f[i1][j] && (s[i1]=p[j1]  p[j1]=.)f[i-1][j]\ \&\&\ (s[i-1] = p[j-1]\ ||\ p[j-1] = .) 即 (abbb,ab*),或者 (abbb,ab* / a.*)
  • 思考輸出f[n][m]f[n][m]

還是有點複雜的,如果沒有正則表達式基礎的同學可能會有點暈,可以放一放…

class Solution {
    public boolean isMatch(String S, String P) {
        char s[] = S.toCharArray(), p[] = P.toCharArray();
        int n = s.length, m = p.length;
        boolean f[][] = new boolean[n+1][m+1];
        f[0][0] = true;
        for (int j = 2; j <= m; j++) 
            f[0][j] = f[0][j-2] && p[j-1] == '*';

        for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            if (s[i-1] == p[j-1] || p[j-1] == '.') {
                f[i][j] = f[i-1][j-1];
            } else if (p[j-1] == '*') {
                f[i][j] = f[i][j-2] || f[i-1][j] && (s[i-1] == p[j-2] || p[j-2] == '.');
            }
        }
        
        return f[n][m];
    }
}

複雜度分析

  • 時間複雜度:O(n×m)O(n × m)
  • 空間複雜度:O(n×m)O(n × m)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章