【劍指offer】52. 正則表達式匹配

問題描述

請實現一個函數用來匹配包括’.‘和’‘的正則表達式。模式中的字符’.‘表示任意一個字符,而’'表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"abaca"匹配,但是與"aa.a"和"ab*a"均不匹配

思路

遞歸着剛吧。沒辦法了。這種在某種情況下有好幾種選擇的,只能用遞歸硬剛。 很熟悉遞歸之後可以把遞歸改成動態規劃。
遞歸。 (方法一)
動態規劃,大神的思路。我這個腦子怕是不行了。 (方法二)
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

方法一

import java.util.*;
public class Solution {
    public boolean match(char[] str, char[] pattern) {
        if(str.length == 0 && pattern.length == 0) return true;
        if(str.length != 0 && pattern.length == 0) return false;
        if(pattern.length > 1 && pattern[1] == '*'){
            if(str.length > 0 && (str[0] == pattern[0] || pattern[0] == '.')){
                return match(Arrays.copyOfRange(str,1,str.length),Arrays.copyOfRange(pattern,2,pattern.length))
                        || match(Arrays.copyOfRange(str,0,str.length),Arrays.copyOfRange(pattern,2,pattern.length))
                        || match(Arrays.copyOfRange(str,1,str.length),Arrays.copyOfRange(pattern,0,pattern.length));
            }else{
                return match(Arrays.copyOfRange(str,0,str.length),Arrays.copyOfRange(pattern,2,pattern.length));
            }
        }
        if(str.length > 0  && (str[0] == pattern[0] || pattern[0] == '.')){
            return match(Arrays.copyOfRange(str,1,str.length),Arrays.copyOfRange(pattern,1,pattern.length));
        }
        return false;
    }
}

這個代碼能A過牛客 , A不過leetcode, 因爲遞歸實在是太慢了。 得空減減枝可以通過leetcode.

方法一-自己實現的

class Solution {
    public boolean isMatch(String s, String p) {
        if(s.length() == 0 && p.length() == 0) return true;
        if(p.length() == 0) return false;
        if(s.length() == 0){
            if(p.length() >= 2 && p.charAt(1) == '*') return isMatch(s,p.substring(2));
            return false;
        }
        if(p.length() == 1 || p.charAt(1) != '*'){
            // 長度爲1, 或者p[1]不是*
            if(p.charAt(0) == '.' || p.charAt(0) == s.charAt(0)) return isMatch(s.substring(1),p.substring(1));
            return false;
        }else{
            // 第二個是*的情況
            if(s.charAt(0) == p.charAt(0) || p.charAt(0) == '.'){
                return isMatch(s,p.substring(2))||isMatch(s.substring(1),p.substring(2))||isMatch(s.substring(1),p);
            }
            return isMatch(s,p.substring(2));
        }
    }
}

方法一-再次提速

class Solution {
    public boolean isMatch(String s, String p) {
        if(s.length() == 0){
            // 只有形如a*b*c*的才能通過
            if((p.length()&1) == 1) return false;
            for(int i = 1; i < p.length(); i+=2){
                if(p.charAt(i) != '*'){
                    return false;
                }
            }
            return true;
        }
        // 正則串耗盡
        if(p.length() == 0) return false;
        // 如果p的長度爲1, 或者長度大於1但是第二位不是*
        if(p.length() == 1 || p.charAt(1) != '*'){
            // 匹配上
            if(p.charAt(0) == '.' || s.charAt(0) == p.charAt(0)) return isMatch(s.substring(1),p.substring(1));
            return false;
        }
        // return 分別是貪婪匹配和惰性匹配的情況
        if(s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') return isMatch(s.substring(1),p)||isMatch(s,p.substring(2));
        // 失配了
        return isMatch(s,p.substring(2));

    }
}

方法二

class Solution {
    public boolean isMatch(String s, String p) {
        // dp[i][j] 代表 s 的前 i 個和 B 的前 j 個能否匹配
        // 之所以用dp[s.length+1][p.length+1]是爲了好處理空串
        boolean[][] dp = new boolean[s.length()+1][p.length()+1];
        for(int i = 0; i <= s.length(); i++){
            for(int j = 0; j <= p.length(); j++){
                if(j == 0){
                    dp[i][j] = i == 0; // 還沒有開始匹配正則
                }else{
                    if(p.charAt(j-1) != '*'){
                        if(i > 0 && (s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '.')){
                            dp[i][j] = dp[i-1][j-1]; // 向前走一位的情況
                        }
                    }else{
                        // 向前走兩位的情況
                        // p.charAt(j-1) == *
                        if(j > 1) dp[i][j] |= dp[i][j-2]; // 放棄這兩位p
                        if(i > 0 && j > 1 && (s.charAt(i-1) == p.charAt(j-2) || p.charAt(j-2) == '.')){
                            dp[i][j] |= dp[i-1][j]; // 匹配上了, 由於之前已經|過了放棄p的情況, 所以這裏只需要|走一個s的情況
                        }
                    }
                }
            }
        }
        return dp[s.length()][p.length()];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章