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 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。

猜你喜欢

转载自www.cnblogs.com/yshi12/p/9691858.html