1. 程式人生 > >leetcode 10-Regular Expression Matching(hard)

leetcode 10-Regular Expression Matching(hard)

!= false 手動 clas mean 邏輯 win color 教材

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 *.

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)