LeetCode10.正则表达式匹配

  本题为困难题,看了很久才看懂,题目如下:

  注意,*和前面的字符是一个整体,如果不进行匹配的话两个字符都可以去掉。

  思路:1.两个序列进行匹配,而且它们还有递推的关系,都应该考虑使用动态规划

     2.动态规划创建二维数组dp[i][j],但要注意应该比两个字符串长度多出一位,i和j为0表示空的情况,主要目的是为了方便创建dp数组的初始值

     3.具体办法:

        3.1.初始化,dp[0][0]=true,dp[0][j](j!=0)=false;很好理解

        3.2.当遍历到i和j时,两者相等或p遍历到"."的位置,可以匹配,那么如果前一位也能匹配的话就为true

        3.3.当j指向的是*时:分情况讨论:

          3.3.1.s[i]!=p[j-1],即*代表的字符不能与相应的i位匹配,那应该考虑去掉*和前面的字符,即匹配0次的情况,如下:

          

          这个时候dp[i][j]=dp[i][j-2].

          3.3.2.此时若s[i]==p[j-1],即s[i]可以和*前面的字符匹配,这个时候就会出现到底应该匹配几次的问题,例如s="caaab",p="ca*ab",此时i=j=3,我们的动态规划是从前往后遍历的,只能由前面的状态来推导,我们可以把i往前移动,一直到s[i]不等于p[j-1],如果这里匹配不上的话,那么之后的匹配不可能成功,反过来,dp[i][j]的状态完全可以前推到s[i]不等于p[j-1]时的状态,由其决定。假设s[i1]!=p[j-1],而i1到i之间的所有位都等于p[j-1]的话,从i1到j之间所有状态都由dp[i1][j]决定,所以dp[i][j]完全可以由dp[i-1][j]来决定,就算i-1和i位相等,那么最终状态肯定也是一样的。故dp[i][j]=dp[i-1][j]。如下:

                  

     代码如下:

    

class Solution {
    public boolean isMatch(String s, String p) {
        int m=s.length();
        int n=p.length();
        boolean[][] dp=new boolean[m+1][n+1];
        dp[0][0]=true;
        for(int i=0;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(p.charAt(j-1)=='*'){
                    dp[i][j]=dp[i][j-2];
                    if(match(s,p,i,j-1))
                        dp[i][j]=dp[i][j]||dp[i-1][j];
                }else{
                    if(match(s,p,i,j))
                        dp[i][j]=dp[i-1][j-1];
                }
            }
        }
        return dp[m][n];
    }
    boolean match(String s,String p,int i,int j){
        if(i==0) return false;
        return s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.';
    }
}

   

原文地址:https://www.cnblogs.com/lzjdsg/p/14660803.html