LeetCode 10 正則表達式匹配(難度: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 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

正則表達式匹配,關鍵就是匹配這倆字。首先,有兩個對象,比較這兩個對象,只有一模一樣才叫做匹配。從 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 *.

輸入串s     可爲空 或者 只包含小寫字母 (a-z) 

樣品 p        可爲空 或者 包含唯一一個小寫字母(a-z)和    ' . '      ' * '    這兩個特殊字符

 

'.' Matches any single character.                                '.' 可變成任意一個單字符

'*' Matches zero or more of the preceding element.  '*' 可讓在其最前面的一個字符重複 0 或 n 次 (0 次表示其前一個字符消失)

             

第一種解法: 遞歸

package pers.leetcode;

/**
 * LeetCode 10 正則表達式匹配
 * 難度: Hard
 *
 * @author 朱景輝
 * @date 2019/3/21 9:49
 */
public class RegularExpressionMatching {
    public static void main(String[] args) {
        String s = "ab";
        String p = ".*c";
        System.out.println("是否匹配: " + isMatch(s, p));
    }

    public static boolean isMatch(String text, String pattern){
        // 先處理特殊情況,pattern 爲空的情況下,text爲空返回true,否則返回false
        if (pattern.isEmpty()){
            return text.isEmpty();
        }
        // 首先比較雙方第一個字符是否相同,2 種情況
        // 1. 兩者第一個字符相同
        // 2. pattern 的第一個字符是 '.'
        boolean first_match = (!text.isEmpty() && (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));

        // 遞歸處理兩種情況
        // 1. pattern長度大於等於 2 ,且第 2 個字符爲'*'
        // 2.  要麼 pattern 長度爲1,要麼長度大於等於 2,但第二個字符不爲 '*'
        if (pattern.length() >= 2 && pattern.charAt(1) == '*'){
            // 這裏返回也有兩種情況
            // 1. '*' 將其前一個字符置空,再從 text 的第一個字符 與 pattern 的第三個字符匹配
            // 2. '*' 目前重複 1 次, 與 text 第一個字符匹配到了,再用 text 的第二個字符 與 pattern 的第一個字符匹配
            return (isMatch(text, pattern.substring(2)) || (first_match && isMatch(text.substring(1), pattern)));
        }else {
            // 只有雙方第一個字符相同 且 剩餘字符匹配 才返回 true
            return first_match && isMatch(text.substring(1), pattern.substring(1));
        }
    }
}

運行結果:

第二種解法:動態規劃。。。現在不想寫了

 

2019/9/22 補上

    /**
     * 動態規劃
     *
     * @param text 給定字符串
     * @param pattern 匹配字符串
     * @return 匹配結果
     */
    public static boolean isMatch2(String text, String pattern){
        boolean[][] dp = new boolean[text.length() + 1][pattern.length() +1];
        dp[text.length()][pattern.length()] = true;

        for (int i = text.length(); i >= 0; i--){
            for (int j = pattern.length() - 1; j>= 0; j--){
                // 雙方最後一個字符是否相同 或者 pattern 最後一個字符爲 '.'
                boolean first_match = (i < text.length() && (pattern.charAt(j) == text.charAt(i) || pattern.charAt(j) == '.'));

                // 1. 從 pattern 倒數第二個字符起, 凡是等於 '*' 的情況
                // 2. 不等於 '*'
                if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
                    dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
                }else {
                    dp[i][j] = first_match && dp[i+1][j+1];
                }
            }
        }
        return dp[0][0];
    }

 

明顯的,動態規劃比遞歸快了 N 倍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章