【LeetCode】解题10:Regular Expression Matching(动态规划解法)

LeetCode解题 10:Regular Expression Matching(动态规划解法)

  • Problem 10: Regular Expression Matching [Hard]
  • 解题思路
  • Solution (Java)

Problem 10: Regular Expression Matching [Hard]

Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.
  • p could be empty and contains only lowercase letters a-z, and characters like . or *.

Example 1:

Input:
s = “aa”
p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.

Example 2:

Input:
s = “aa”
p = “a*”
Output: true
Explanation: ‘*’ means zero or more of the preceding element, ‘a’. Therefore, by repeating ‘a’ once, it becomes “aa”.

Example 3:

Input:
s = “ab”
p = “.*”
Output: true
Explanation: “.*” means “zero or more (*) of any character (.)”.

Example 4:

Input:
s = “aab”
p = “c*a*b”
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches “aab”.

Example 5:

Input:
s = “mississippi”
p = “mis*is*p*.”
Output: false

来源:LeetCode

解题思路

使用动态规划思想。维护数组match[n][m],match[i][j]代表字符串s的前i个和模式p的前j个是否匹配。二重循环遍历sp,match[i][j]根据p[j]和s[i]的关系可以由match[i-1][j-1]等前项转换而来,具体转换公式为:

  1. p [ j ] = s [ i ] p[j] = s[i] p[j]=s[i] 或者 p [ j ] = p[j] = p[j]= '.'时,有
    m a t c h [ i ] [ j ] = m a t c h [ i − 1 ] [ j − 1 ] match[i][j] = match[i-1][j-1] match[i][j]=match[i1][j1]

  2. p [ j ] = p[j] = p[j]= '*'时,情况比较复杂。需要考虑*的前一个字符,即 p [ j − 1 ] p[j-1] p[j1]

    2.1 若 p [ j − 1 ] ≠ s [ i ] p[j-1] \neq s[i] p[j1]=s[i] p [ j − 1 ] ≠ p[j-1] \neq p[j1]= '.',则*只能匹配零个,相当于去掉 p [ j − 1 ] p[j-1] p[j1] p [ j ] p[j] p[j],转换公式为:
    m a t c h [ i ] [ j ] = m a t c h [ i ] [ j − 2 ] match[i][j] = match[i][j-2] match[i][j]=match[i][j2]
    2.2 若 p [ j − 1 ] = s [ i ] p[j-1] = s[i] p[j1]=s[i] 或者 p [ j − 1 ] = p[j-1] = p[j1]= '.',那么*有可能匹配零个或多个。假设当前s###ap###a*,则match[i][j]有可能从不同的前项转移而来:

    i. *匹配多个a的情况,例如:czha|aczha|*。此时s[i]上的a只是a*的延续,转移公式为:
    m a t c h [ i ] [ j ] = m a t c h [ i − 1 ] [ j ] match[i][j] = match[i-1][j] match[i][j]=match[i1][j]
    注意:除了上述例子中*匹配了两个a的情况,转移公式同样适用于匹配一个a的情况。(s = czh|a,p = czha|*,match[i-1][j]代表czhczha*匹配,仍然可以完全匹配。)

    ii. *匹配零个a的情况,例如:czh|aczhaa|*。此时a*是多余的,可以去掉,转移公式为:
    m a t c h [ i ] [ j ] = m a t c h [ i ] [ j − 2 ] match[i][j] = match[i][j-2] match[i][j]=match[i][j2]
    情况i和情况ii中,只要任意一个能匹配上,则 m a t c h [ i ] [ j ] = t r u e match[i][j] = true match[i][j]=true

  3. p [ j ] p[j] p[j]不属于上述任何情况,即 p [ j ] p[j] p[j]不为特殊符号且 p [ j ] ≠ s [ i ] p[j] \neq s[i] p[j]=s[i]时, m a t c h [ i ] [ j ] = f a l s e match[i][j] = false match[i][j]=false

思路参考LeetCode题解

时间复杂度为 O ( n m ) O(nm) O(nm),空间复杂度为 O ( n m ) O(nm) O(nm)

运行结果:
【LeetCode】解题10:Regular Expression Matching(动态规划解法)_第1张图片

要点:动态规划

Solution (Java)

class Solution {
    public boolean isMatch(String s, String p) {
        int n = s.length() + 1;
        int m = p.length() + 1;
        if(n == 1 && m == 1) return true;
        if(n > 1 && m == 1) return false;
        boolean[][] match = new boolean[n][m];
        // initialize
        match[0][0] = true;
        match[0][1] = false;
        for(int mj = 2; mj < m; mj++){
            int j = mj - 1;
            if(p.charAt(j) == '*') match[0][mj] = match[0][mj-2];
            else match[0][mj] = false;
        }
        for(int mi = 1; mi < n; mi++){
            match[mi][0] = false;
        }
        // dp
        for(int mi = 1; mi < n; mi++){
            for(int mj = 1; mj < m; mj++){
                int i = mi - 1;
                int j = mj - 1;
                if(p.charAt(j) == s.charAt(i) || p.charAt(j) == '.'){
                    match[mi][mj] = match[mi-1][mj-1];
                }
                else if(p.charAt(j) == '*'){
                    if(p.charAt(j-1) == s.charAt(i) || p.charAt(j-1) == '.'){
                        match[mi][mj] = match[mi-1][mj] || match[mi][mj-2];
                    }
                    else{
                        match[mi][mj] = match[mi][mj-2];
                    }
                }
                else{
                    match[mi][mj] = false;
                }
            }
        }
        return match[n-1][m-1];
    }
}

你可能感兴趣的:(LeetCode)