剑指Offer-正则表达式的匹配

为君一笑 提交于 2020-02-29 14:10:01

请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

动态规划:
1、首先写出dp矩阵,定义dp矩阵中元素的意义,最好能够画图说明
2、列举矩阵中哥哥元素之间的关系,即状态转移方程,一般为dp[i][j]与dp[i-1][j],dp[i][j-1],dp[i-1][j-1]之间的关系。
3、定义矩阵的初始值。

 public boolean isMatch(String s, String p) {
        if(s==null || p==null) return false;
        int sLen = s.length();
        int pLen = p.length(); 
        //dp[i][j]表示s中前i个字符[0,i-1]与p中的前j个字符[0,j-1]能否匹配
        boolean[][] dp = new boolean[sLen+1][pLen+1];
        dp[0][0] = true;//两个空字符可以相互匹配
        for(int j = 1;j<dp[0].length;j++){ 
            //在p中的第j-1位字符为*时,可以去掉p中的j-1与j-2位字符
            //当dp[0][j-2]为true,也就是p中的[0,j-3]可以与s匹配时,可以将dp[0][j]置为true
            if(p.charAt(j-1)=='*' && dp[0][j-2]){ //p不会出现第一个字符为*的情况,所以不会产生越界错误
                dp[0][j] = true;
            }
        }
        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)){ //如果s[i-1]与p[j-1]相同
                    dp[i][j] = dp[i-1][j-1]; 
                }else{ //如果s[i-1]与p[j-1]不相同
                    if(p.charAt(j-1)=='.'){ //.可以表示任意字符,所以.出现时认为当前位匹配
                        dp[i][j] = dp[i-1][j-1];
                    }else if(p.charAt(j-1)=='*'){
                        if(p.charAt(j-2)!=s.charAt(i-1)){ //p中*的前一位与s中当前位不匹配
                            //*可以p中的j-1与j-2位消失
                            dp[i][j] = dp[i][j-2];
                        }
                        if(p.charAt(j-2)==s.charAt(i-1) || p.charAt(j-2)=='.'){
                            //p中*的前一位与s当前位匹配,或者*的前一位为.
                            //当*表示取前面的0个字符时,s= aa,p = aab* 或p == aa.*,
                            //dp[i][j] = dp[i][j-2]
                            //取一个字符时,s=aab,p=aab*,此时p去掉一位 dp[i][j-1]
                            //取多位字符,s=aabb,p=aab*,相当于s去掉1位,s=aab与p==aab*进行匹配
                            //dp[i][j] = dp[i-1][j]
                            dp[i][j] = dp[i][j-2] || dp[i][j-1] || dp[i-1][j];
                        }
                    }else{//如果p[j-1]处是一个普通字符,p[j-1]无法与s[i-1]匹配
                        dp[i][j] = false;
                    }
            }
        }
    }
        return dp[sLen][pLen];
    }

改进优化当p[j-1]字符为’*'的情况
当p[j-1]字符为*时,不管p[j-2]与s[i-1]是否相同,我们都可以将p[j-1]与p[j-2]去掉。

   dp[i][j] = dp[i][j] || dp[i][j-2];

当p[j-1]字符为时,并且表示多个字符的情况,只有当p[j-2]==s[i-1]或者 '‘之前的符号为’.'时。

 if(p.charAt(j-2)==s.charAt(i-1) || p.charAt(j-2)=='.'){
                            dp[i][j] =  dp[i][j-1] || dp[i-1][j];
                        }

代码优化:

 if(p.charAt(j-2)==s.charAt(i-1) || p.charAt(j-2)=='.'){
                            //取一个字符时,s=aab,p=aab*,此时p去掉一位 dp[i][j-1]
                            //取多位字符,s=aabb,p=aab*,相当于s去掉1位,s=aab与p==aab*进行匹配
                            //dp[i][j] = dp[i-1][j]
                            dp[i][j] =  dp[i][j-1] || dp[i-1][j];
                        }
                           dp[i][j] = dp[i][j] || dp[i][j-2];
                        
                        //不管p中*前一位是否与s的当前位相同,可以直接将p中*与*的前一位去掉
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!