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 precedeng 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

Thinking:

  • Method1:通过回溯法
class Solution {
    public boolean isMatch(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        return myMatch(s, sLen - 1, p, pLen - 1);
    }
    public static boolean myMatch(String s, int i, String p, int j){
        if(j == -1)
            if(i == -1) return true;
        else return false;
        if(p.charAt(j) == '*'){
            if( i > -1 && (p.charAt(j - 1) == s.charAt(i) || p.charAt(j - 1) == '.')){
                if(myMatch(s, i - 1, p, j))
                    return true;
            }
            return myMatch(s, i, p, j - 2);
        }
        if(i > -1 && j > -1 && (p.charAt(j) == '.' || p.charAt(j) == s.charAt(i)))
            return myMatch(s, i - 1, p, j - 1);
        return false;
    }
}

二刷

  1. 使用动态规划。
    • 初始化
      • dp[0][0] = true, 当两个字符串都是空串,一定是匹配的。
      • 当s为空串,如果p当前字符是’’, 当前结果dp[0][j]和dp[0][j - 2]相同,因为可以代表出现0次。
    • 动态规划
      • 当p的当前字符是.或者和s当前字符相同,dp[i][j]=dp[i-1][j-1],前面一个字符匹配则当前字符匹配。
      • 当p的当前字符是*
        • 首先设置dp[i][j] = dp[i][j - 2], 说明前一个字符循环0次。
        • 如果s的当前字符等于p的前一位字符, dp[i][j] = dp[i - 1][j],如果前一位匹配则当前也匹配。
class Solution {
    public boolean isMatch(String s, String p) {
        if(s == null || p == null) return false;
        int len1 = s.length(), len2 = p.length();
        boolean dp[][] = new boolean[len1 + 1][len2 + 1];
        dp[0][0] = true;
        for(int i = 1; i <= len2; i++)
            if(p.charAt(i - 1) == '*') dp[0][i] = dp[0][i - 2];
        for(int i = 1; i <= len1; i++){
            char c1 = s.charAt(i - 1);
            for(int j = 1; j <= len2; j++){
                char c2 = p.charAt(j - 1);
                if(match(c1, c2)){
                    dp[i][j] = dp[i - 1][j - 1];
                }else{  // c2 == '*'
                    if(p.charAt(j - 1) == '*'){
                        dp[i][j] = dp[i][j - 2];   //skip current
                        if(j > 1 && match(c1, p.charAt(j - 2)))
                            dp[i][j] |= dp[i - 1][j];
                    }
                }
            }
        }
        return dp[len1][len2];
    }
    private boolean match(char c1, char c2){
        return c2 == '.' || c1 == c2;
    }
}

三刷

class Solution {
    public boolean isMatch(String s, String p) {
        if(s == null || p == null) return false;
        int sLen = s.length(), pLen = p.length();
        boolean[][] dp = new boolean[sLen + 1][pLen + 1];
        dp[0][0] = true;
        for(int i = 1; i <= pLen; i++)
            if(p.charAt(i - 1) == '*') dp[0][i] = dp[0][i - 2];
        for(int i = 1; i <= sLen; i++){
            char c1 = s.charAt(i - 1);
            for(int j = 1; j <= pLen; j ++){
                char c2 = p.charAt(j - 1);
                if(check(c1, c2)) dp[i][j] = dp[i - 1][j - 1];
                else{
                    if(c2 == '*'){
                        dp[i][j] = dp[i][j - 2];
                        if(j > 1 && check(c1, p.charAt(j - 2)))
                            dp[i][j] |= dp[i - 1][j];	//唯一的难点就是为什么是j,是因为前一位也可能是通过匹配得到的。
                    }
                }
            }
        }
        return dp[sLen][pLen];
    }
    private boolean check(char c1, char c2){
        return c1 == c2 || c2 == '.';
    }
}