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; } } }