leetcode解题笔记:Regular Expression Matching

10.Regular Expression Matching

‘.’ 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

这是一道有关正则表达式的题目。其中“.”代表任意一个字符,“*”代表其前面的字符可以出现任意次(包括0次)。

每次从字符串拿出一个字符和模式中的字符去匹配

  • 如果两个字符相等或者模式中的字符为“.”,此时这两个字符匹配成功,那么接着匹配后面的字符
  • 当模式中的字符为*时处理起来比较困难。
    • 如果“* ”之前的字符a和字符串中字符b不匹配(即a,b不相等或a不是”.”),则应该忽略掉“ a*”,接着向后匹配
    • 如果“* ”之前的字符a和字符串中字符b匹配(即a,b相等或a是”.”),那么这又有几种情况可以选择:
      • b和“a*”匹配一次,然后接着往后匹配
      • b和“a*”匹配多次,即接着匹配b的下一个字符和a*
      • b不和“a*”匹配,接着将b和a*后面的字符进行匹配

顺着这个思路可以写出一个解法:

public class Solution {
    public boolean isMatch(String s, String p) {
        return match(s,p,0,0);
    }
    public boolean match(String s, String p,int i,int j){
        if(i==s.length() && j == p.length()) return true;
        if(i!=s.length() && j == p.length()) return false;
        //当下一个匹配字符是*时
        if(j!=p.length()-1 && p.charAt(j+1) == '*'){
            //如果当前匹配字符与字符串字符相等
            if(i != s.length() && (p.charAt(j) == '.' ||s.charAt(i) == p.charAt(j))){
                //还是当前匹配模式,匹配下一个字符
                return match(s,p,i+1,j)
                //到下一次匹配,即a*只匹配一次
                || match(s,p,i+1,j+2)
                //忽略这个*匹配模式,即a*匹配0次,匹配当前字符和下一匹配字符
                || match(s,p,i,j+2);
            }else{
                //当前字符和匹配字符不等,直接忽略这个匹配模式,匹配下一个
                return match(s,p,i,j+2);
            }
        }
        if(i != s.length() && (p.charAt(j) == '.' ||s.charAt(i) == p.charAt(j))){
            return match(s,p,i+1,j+1);
        }
        return false;
    }
}

但这种方法极慢,应该是在 return match(s,p,i+1,j)|| match(s,p,i+1,j+2)|| match(s,p,i,j+2); 这个过程中递归层次会过深。

考虑使用动态规划来解决这个问题。
dp[i][j]代表字符串前i个字符和模式前j个字符的匹配结果。
(这个下标的对应关系搞得我很混乱啊啊啊 (ノಠ益ಠ)ノ彡┻━┻)
首先可以根据找出的匹配规律写出如下规则:

1, If p.charAt(j) == s.charAt(i) :  dp[i][j] = dp[i-1][j-1];
2, If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1];
3, If p.charAt(j) == '*': 
    1   if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2]  
    //in this case, a* only counts as empty
    2   if p.charAt(j-1) == s.charAt(i) or p.charAt(j-1) == '.':
    dp[i][j] = dp[i-1][j]    
    //in this case, a* counts as multiple a 
    or dp[i][j] = dp[i][j-1]   
    // in this case, a* counts as single a
    or dp[i][j] = dp[i][j-2]   
    // in this case, a* counts as empty
public 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 i = 2; i <= p.length(); i++) {
        if (p.charAt(i-1) == '*' && dp[0][i-2]) {
            dp[0][i] = true;
        }
    }
        for(int i=1;i<=s.length();i++){
            for(int j=1;j<=p.length();j++){
                if(p.charAt(j-1) == '.'){
                    dp[i][j] = dp[i-1][j-1];
                }
                if(p.charAt(j-1) == s.charAt(i-1)){
                    dp[i][j] = dp[i-1][j-1];
                }
                if(p.charAt(j-1) == '*'){
                    if(p.charAt(j-2) != s.charAt(i-1)&& p.charAt(j-2)!='.'){
                        dp[i][j] = dp[i][j-2];
                    }else{
                        dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i][j-2];
                    }
                }


            }
        }
        return dp[s.length()][p.length()];
    }

}

动规算法明显加快,因为是根据前面的结果计算当前的结果,不会有前面的递归层次深的问题。
虽然思想是一样的,我总是觉得动规的代码写出来不顺,不是那么容易理解。可能因为前一个是自底向上,动规有点自顶向下的感觉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值