leetcode 10-Regular Expression Matching(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 lettersa-z
p
could be empty and contains only lowercase lettersa-z
, and characters like.
or*.
cases:
two pointers, one for s (sp), one for p (pp)
1. p[pp] is letter:
(1)p[pp+1]!=‘*‘, s[sp]!=p[pp] return false;
(2)p[pp+1]=‘*‘, ‘*‘ means zero all more p[pp], we can jump p[pp] and p[pp+1] or iterate through all continuous and equals p[pp] in s, and continue matching
2. p[pp]=‘.‘:
(1)p[pp+1]!=‘*‘: sp++,pp++;
(2)p[pp+1]==‘*‘: sp can iterate through all the following letters in s to see whether there is a match.
3. p[pp]=‘*‘ return false;
註意 在iterate的時候,在用while的時候一定要記得寫循環變量的變化,不要以為是for循環會自己加一,要不然會陷入死循環!
class Solution { public boolean isMatch(String s, String p) {if(s.length()==0 && p.length()==0) return true; else if(p.length()==0) return false; return findMatch(s, p, 0, 0); } public boolean findMatch(String s, String p, int sp, int pp){ if(sp==s.length()&&pp==p.length()) return true; else if(pp==p.length()) return false; if(p.charAt(pp)!=‘*‘&&p.charAt(pp)!=‘.‘){ if(pp==p.length()-1||p.charAt(pp+1)!=‘*‘){ if(sp==s.length()||s.charAt(sp)!=p.charAt(pp)) return false; return findMatch(s, p, sp+1, pp+1); } else{ if(findMatch(s,p,sp,pp+2)) return true; while(sp<s.length()&&s.charAt(sp)==p.charAt(pp)){ if(findMatch(s,p,sp+1,pp+2)) return true; sp++; } return false; } } else if(p.charAt(pp)==‘.‘){ if(sp==s.length()&&(pp<p.length()-1&&p.charAt(pp+1)!=‘*‘)) return false; if(pp==p.length()-1||p.charAt(pp+1)!=‘*‘) return findMatch(s, p, sp+1,pp+1); else{ while(sp<=s.length()){ if(findMatch(s,p,sp,pp+2)) return true; sp++; } return false; } } else return false; } }
以上為自己瞎折騰改了半天的代碼,需要考慮的情況太多,邏輯在細節和corner case處比較亂,反面教材!
以下參考leetcode大神代碼:
https://leetcode.com/problems/regular-expression-matching/discuss/5651/Easy-DP-Java-Solution-with-detailed-Explanation
DP:
string s, i
string p, j
2D dp array
1. s.charAt(i)==p.charAt(j): dp[i][j]=dp[i-1][j-1]
2. p.charAt(j)==‘.‘: dp[i][j]=dp[i-1][j-1]
3. p.charAt(j)==‘*‘:
two cases:(1)s.charAt(i)!=p.charAt(j-1): dp[i][j]=dp[i][j-2]
(2)s.charAt(i)==p.charAt(j-1): dp[i][j]=dp[i][j-2] //in this case, a* counts as empty
or dp[i][j]=dp[i][j-1] //in this case, a* counts as single a
or dp[i][j]=dp[i-1][j] //in this case, a* counts as multiple a
class Solution { public boolean isMatch(String s, String p) { if(s==null||p==null) return false; boolean[][] dp=new boolean[s.length()+1][p.length()+1]; dp[0][0]=true; for(int j=1;j<dp[0].length;j++){ if(j>1&&p.charAt(j-1)==‘*‘) dp[0][j]=dp[0][j-2]; } for(int i=1;i<dp.length;i++){ for(int j=1;j<dp[0].length;j++){ if(s.charAt(i-1)==p.charAt(j-1) || p.charAt(j-1)==‘.‘) dp[i][j]=dp[i-1][j-1]; else if(p.charAt(j-1)==‘*‘){ if(j>1){ if(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)==‘.‘){ dp[i][j]=dp[i][j-2]||dp[i][j-1]||dp[i-1][j]; } else{ dp[i][j]=dp[i][j-2]; } } } } } return dp[s.length()][p.length()]; } }
非常簡潔明晰,dp的時候首先註意初始化(0,0)的情況,然後考慮分別為0的情況的初始化,一定要註意的是,dp矩陣的長寬都是比string的長度大1的,在寫的時候,dp[i][j],對於相應的string中,下標一定不要忘記是i-1,j-1之類。
部分細節處做了修改:雖然leetcode測試case沒有 s="", p="*" 類似情況,所以鏈接中的熱評第一代碼可以ac,但手動輸入這些case時系統給出的答案是正確的,鏈接所給的代碼會報錯,覺得也需要考慮這些corner case。
leetcode 10-Regular Expression Matching(hard)