ホーム LeetCode. 10. Regular Expression Matching
記事
キャンセル

LeetCode. 10. Regular Expression Matching

問題

動的計画法

この問題で使うパターン演算子は 2 つだけです。. は任意の 1 文字に一致し、* は直前の原子を 0 回以上繰り返したものに一致します。そのため、* は直前の原子と組み合わせて処理し、単独で使ったりパターンのより前の部分に適用したりすることはありません。問題ではすべてのパターンが有効であると保証されるため、各 * の直前には原子があります。

dp[i][j] を、s の先頭 i 文字と p の先頭 j 文字が一致するかどうかを表す値とします。答えは dp[s.length()][p.length()] です。空の接頭辞同士は一致するため、dp[0][0] は true です。空文字列と一致する空でないパターンは、末尾の原子とアスタリスクの組を読み飛ばせる場合に限られます。有効な各 x* の組について、dp[0][j] = dp[0][j - 2] と初期化します。

パターン文字が * でなければ、現在の入力文字と一致する必要があります(同じリテラル文字、または .)。さらに、直前の接頭辞同士も一致していなければなりません。つまり、dp[i][j] = matches(s[i - 1], p[j - 1]) && dp[i - 1][j - 1] です。

x* の組には 2 通りの処理があります。x を 0 回使う場合は dp[i][j - 2] を使います。または、一致する入力文字を 1 文字消費し、同じパターンの組をさらに繰り返せるように残します。この場合の条件は matches(s[i - 1], p[j - 2]) && dp[i - 1][j] です。

テーブルの計算時間は O(|s||p|)、空間計算量も O(|s||p|) です。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
        dp[0][0] = true;

        for (int j = 2; j <= n; j++) {
            if (p.charAt(j - 1) == '*') {
                dp[0][j] = dp[0][j - 2];
            }
        }

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                char patternChar = p.charAt(j - 1);
                if (patternChar == '*') {
                    char atom = p.charAt(j - 2);
                    dp[i][j] = dp[i][j - 2]
                            || (matches(s.charAt(i - 1), atom) && dp[i - 1][j]);
                } else {
                    dp[i][j] = matches(s.charAt(i - 1), patternChar)
                            && dp[i - 1][j - 1];
                }
            }
        }

        return dp[m][n];
    }

    private boolean matches(char input, char atom) {
        return atom == '.' || input == atom;
    }
}
この記事は著者により CC BY 4.0 ライセンスで公開されています。