1. 程式人生 > >LEETCODE 10 Regular Expression Matching (JAVA題解)

LEETCODE 10 Regular Expression Matching (JAVA題解)

https://leetcode.com/problems/regular-expression-matching/

原題連結。

題意解析:

實現正則表示式的 '.' 和 '*' 匹配功能

‘.’ 可以匹配任意字元

'c*' 可以匹配0個,1個,或者多個連續的c字元,只有與其他字元一起,‘*’才會發揮作用

解題思路:

首先要明確,這類題目是一種幾乎不能一次AC的題目,除非你自己設計的測試案例非常好,可以在提交之前就考慮到所有奇葩的情況

看下面的一個測試案例:

“abcdabcdabcdabcdac”

'a*abcda*abcda*abcda*abcda*c'

熟悉正則表示式的朋友,一眼能看出它是能匹配的。

問題在於,模式字串中有多個a*,而在這多個a*都可以表示一個a的,但當且僅當前四個表示0個a,第五個表示1個a的時候,才能使整個字串匹配。

一般在做字串匹配的時候,都是從左往右匹配的,那麼,怎麼可以知道,我應不應該匹配目前可以匹配的字元呢?

具體來說,就是,當地一個a*遇到第一個a的時候,它應該表示0個a,還是表示1個a?

不到後面是不知道的,所以,這涉及到回退的問題,凡是涉及到回退的問題,就要用到遞迴。

遞迴演算法是解決這個問題的第一大思路。

涉及到遞迴演算法,就要確定兩點:遞迴出口和遞迴過程

遞迴出口,各位朋友可以多試幾個測試案例來確定,也就是多提交幾次,當然有些遞迴出口是容易想到的,例如當兩個字串的索引都到達尾部的時候

遞迴體,要考慮幾個分支情況。

1.普通字元以及‘.’之間的匹配(不涉及'*')

     1.1匹配的話應該怎樣做

     1.2不匹配的話應該怎樣做

2.涉及到‘*’的匹配

     2.1匹配的話應該怎樣做

     2.2不匹配的話應該怎樣做

普通的遞迴是一定會超時的,所以需要剪枝,而這裡的剪枝的方法就是記憶化遞迴。記憶化遞迴就是用一個數組記錄狀態的返回結果。

點到即止

解題程式碼如下(本人初哥,程式碼寫得醜,懇請各位指正):

public boolean isMatch(String s, String p) {
        
        int index1=0,index2=0;
        Boolean[][] remember=new Boolean[s.length()+1][p.length()+1];
        for(int i=0;i<s.length()+1;i++){
            for(int j=0;j<p.length()+1;j++){
                remember[i][j]=null;
            }
        }
        
        return isMatch(s,p,0,0,remember);
    }
    
    private Boolean isMatch(String s,String p,int index1,int index2,Boolean[][] remember){
        //採用記憶化遞迴搜尋方法
        if(remember[index1][index2]!=null){
            return remember[index1][index2];
        }
        if(index1==s.length() && index2==p.length()){
            return remember[index1][index2]=true;
        }
        if(index1!=s.length() && index2==p.length()){
            return remember[index1][index2]=false;
        }
        if(index1==s.length() && index2!=p.length()){
            if(index2<p.length()-1 && p.charAt(index2+1)=='*'){
                return remember[index1][index2+2]=isMatch(s,p,index1,index2+2,remember);
            }else{
                return remember[index1][index2]=false;
            }
        }
        if(index2<p.length()-1 && p.charAt(index2+1)=='*'){
            if(s.charAt(index1)==p.charAt(index2) || p.charAt(index2)=='.'){
                return (remember[index1+1][index2]=isMatch(s,p,index1+1,index2,remember)) ||
                       (remember[index1][index2+2]=isMatch(s,p,index1,index2+2,remember)) ||
                       (remember[index1+1][index2+2]=isMatch(s,p,index1+1,index2+2,remember));
            }else{
                return remember[index1][index2+2]=isMatch(s,p,index1,index2+2,remember);
            }
        }else{
            if(s.charAt(index1)==p.charAt(index2) || p.charAt(index2)=='.'){
                return remember[index1+1][index2+1]=isMatch(s,p,index1+1,index2+1,remember);
            }else{
                return false;
            }
        }
    }