Regular Expression Matching

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

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
解法一:

实现支持 ' . '和 ' * '的正则表达式。

' . ' 匹配任何单字符。

' * '匹配0或多个前向元素。

使用递归进行判断。总体上可以分成两种情况,一种是以 ' * ‘开头的,另一种不是。

基本思路就是先看字符串s和p的从i和j开始的子串是否匹配,用递归的方法直到串的最后,最后回溯回来得到结果。假设现在走到s的i位置,p的j位置,情况分为下列两种: 
(1)p[j+1]不是'*'。情况比较简单,只要判断当前s的i和p的j上的字符是否一样(如果有p在j上的字符是'.',也是相同),如果不同,返回false,否则,递归下一层i+1,j+1; 
(2)p[j+1]是'*'。那么此时看从s[i]开始的子串,假设s[i],s[i+1],...s[i+k]都等于p[j]那么意味着这些都有可能是合适的匹配,那么递归对于剩下的(i,j+2),(i+1,j+2),...,(i+k,j+2)都要尝试(j+2是因为跳过当前和下一个'*'字符)。

public class Solution {     public boolean isMatch(String s, String p) {         if(p.length() == 0)                 return s.length() == 0;         if(p.length() == 1 || p.charAt(1) != '*'){               if(s.length()  < 1 || (p.charAt(0) != '.' && s.charAt(0) != p.charAt(0)))                 return false;               return isMatch(s.substring(1),p.substring(1));         }else{               int i = -1;               while(i < s.length() && (i < 0 || p.charAt(0) == '.' || p.charAt(0) == s.charAt(i))){                 if(isMatch(s.substring(i+1),p.substring(2)))                   return true;                 i++;               }           return false;         }     } }
解法二:
接下来我们考虑如何优化brute force算法,熟悉动态规划的朋友可能发现了,其实这个思路已经很接近动态规划了。动态规划基本思想就是把我们计算过的历史信息记录下来,等到要用到的时候就直接使用,不用重新计算。在这个题里面,假设我们维护一个布尔数组res[i][j],代表s的前i个字符和p的前j个字符是否匹配(注意这里res的维度是s.length()+1,p.length()+1)。递推公式跟上面类似,分三种种情况: 
(1)p[j+1]不是'*'。情况比较简单,只要判断如果当前s的i和p的j上的字符一样(如果有p在j上的字符是'.',也是相同),并且res[i][j]==true,则res[i+1][j+1]也为true,res[i+1][j+1]=false; 
(2)p[j+1]是'*',但是p[j]!='.'。那么只要以下条件有一个满足即可对res[i+1][j+1]赋值为true: 
   1)res[i+1][j]为真('*'只取前面字符一次); 
   2)res[i+1][j-1]为真('*'前面字符一次都不取,也就是忽略这两个字符); 
   3)res[i][j+1] && s[i]==s[i-1] && s[i-1]==p[j-1](这种情况是相当于i从0到s.length()扫过来,如果p[j+1]对应的字符是‘*’那就意味着接下来的串就可以依次匹配下来,如果下面的字符一直重复,并且就是‘*’前面的那个字符)。 
(3)p[j+1]是'*',并且p[j]=='.'。因为".*"可以匹配任意字符串,所以在前面的res[i+1][j-1]或者res[i+1][j]中只要有i+1是true,那么剩下的res[i+1][j+1],res[i+2][j+1],...,res[s.length()][j+1]就都是true了。 
这道题有个很重要的点,就是实现的时候外层循环应该是p,然后待匹配串s内层循环扫过来。代码如下:
public class Solution {
    public boolean isMatch(String s, String p) {
        if(s.length()==0 && p.length()==0)  
        return true;  
    if(p.length()==0)  
        return false;  
    boolean[][] res = new boolean[s.length()+1][p.length()+1];  
    res[0][0] = true;  
    for(int j=0;j<p.length();j++)  
    {  
        if(p.charAt(j)=='*')  
        {  
            if(j>0 && res[0][j-1]) res[0][j+1]=true;  
            if(j<1) continue;  
            if(p.charAt(j-1)!='.')  
            {  
                for(int i=0;i<s.length();i++)  
                {  
                    if(res[i+1][j] || j>0&&res[i+1][j-1]   
                    || i>0 && j>0 && res[i][j+1]&&s.charAt(i)==s.charAt(i-1)&&s.charAt(i-1)==p.charAt(j-1))  
                        res[i+1][j+1] = true;  
                }  
            }  
            else
            {  
                int i=0;  
                while(j>0 && i<s.length() && !res[i+1][j-1] && !res[i+1][j])  
                    i++;  
                for(;i<s.length();i++)  
                {  
                    res[i+1][j+1] = true;  
                }  
            }  
        }  
        else
        {  
            for(int i=0;i<s.length();i++)  
            {  
                if(s.charAt(i)==p.charAt(j) || p.charAt(j)=='.')  
                    res[i+1][j+1] = res[i][j];  
            }  
        }  
    }  
    return res[s.length()][p.length()];  
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值