LeetCode之正则表达式匹配

今天做到LeetCode中的第十题:正则表达式匹配,难度级别为困难,匹配情况复杂,思路不难理解,但是仍无从下手,暂且先记录一下,改日再做研究理解。
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

  • ‘.’ 匹配任意单个字符
  • ‘*’ 匹配零个或多个前面的那一个元素
    所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
    在这里插入图片描述在这里插入图片描述解题思路:
		bool dp(string& s , int i,string& p,int j){
			int m = s.size(), n = p.size();
			//base case
			if(j == n){
				return i == m;	
			}				
			if(i == m){
				if((n - j) % 2 ==1){
					return false;
				}
				for(; j + 1 < n; j += 2){
					if(p[j + 1] != '*'){
						return false;
					}
				}
				return true;
			}
			//记录状态(i,j),消除重叠子问题
			string key = to_string(i) + "," + to_string(j);
			if(memo.count(key)){
				return memo[key];
			}
			bool res = false;
			if(s[i] == p[j] || p[j] == '.'){
				if(j < n-1 && p[j+1] == '*'){
					res = dp(s, i, p, j + 2) || dp(s, i + 1, p, j);
				}else{
					res = dp(s, i + 1, p, j + 1);
				}
			}else{
				if(j < n-1 && p[j + 1] == '*'){
					res=dp(s, i, p, j+2);
				}else{
					res = false;
				}
			}
			//将结果记入备忘录
			memo[key] = res;
			return res;
		}
public static boolean isMatch(String s,String p) {
		if(s==null||p==null) {
			return false;
		}
		int sLen=s.length(),pLen=p.length();
		boolean[][] dp=new boolean[sLen+1][pLen+1];
		dp[0][0]=true;
		//"aab","c*a*b"
		for(int j=1;j<pLen+1;j++) {
			if(p.charAt(j-1)=='*')dp[0][j]=dp[0][j-2];
		}
		for(int i=1;i<sLen+1;i++) {
			for(int j=1;j<pLen+1;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(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)=='.') {
						dp[i][j]=dp[i][j-2]||dp[i-1][j-2]||dp[i-1][j];
					}else {
						dp[i][j]=dp[i][j-2];
					}
				}
			}
		}
		return dp[sLen][pLen];
	}

参考答案:力扣题解

class Solution {
    public boolean isMatch(String s, String p) {
        return recur(s.toCharArray(),p.toCharArray(),s.length()-1,p.length()-1);
    }

    public boolean recur(char[] ss,char[] pp,int sidx,int pidx){
      //结束条件确实恶心,各种idxOutBound
      if(pidx<0){
        return sidx==pidx;
      }
      if(sidx<0){
        while(pidx>=0&&pp[pidx]=='*'){//bug_注意:pidx>=0
          pidx-=2;
        }
        return pidx==sidx;
      }

      //下面逻辑代码不需要考虑idx为负数,就算idx负数,那也是下一个recur去判断.
      if(pp[pidx]!='*'){//不是*好说,要么点,要么字母
        if(pp[pidx]=='.'){//是点,点可以匹配任意,所以直接recur
          return recur(ss,pp,sidx-1,pidx-1);
        }else{
          if(pp[pidx]==ss[sidx]){//s和p的末尾字母,若相同,也是直接recur
            return recur(ss,pp,sidx-1,pidx-1);
          }else{
            return false;//s和p的末尾字母,不相同直接gg,返false
          }
        }
      }else{
        //根据题意:*匹配0个or多个
        if(recur(ss,pp,sidx,pidx-2)) return true;//这是:*匹配0个

        char ctemp=pp[pidx-1];//下面是*匹配多个
        int sidxmove=sidx;
        /**
        * 用p的末尾去匹配s的末尾的1个,2个,3个,4个...不可能匹配掉无限个吧!!用*把ss[0]都匹配掉了应该是极限了
        */
        while(sidxmove>=0&&(ctemp=='.'||ctemp==ss[sidxmove])){//用*匹配掉1个,2个,3个,4个...
          if(recur(ss,pp,sidxmove-1,pidx-2)){
            return true;//加速加速
          }
          sidxmove--;
        }
        return false;//上面加速都不成功,说明没救了
      }

    }
}
class Solution {
    public boolean isMatch(String ss, String pp) {
        // 技巧:往原字符头部插入空格,这样得到 char 数组是从 1 开始,而且可以使得 f[0][0] = true,可以将 true 这个结果滚动下去
        int n = ss.length(), m = pp.length();
        ss = " " + ss;
        pp = " " + pp;
        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();
        // f(i,j) 代表考虑 s 中的 1~i 字符和 p 中的 1~j 字符 是否匹配
        boolean[][] f = new boolean[n + 1][m + 1];
        f[0][0] = true;
        for (int i = 0; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                // 如果下一个字符是 '*',则代表当前字符不能被单独使用,跳过
                if (j + 1 <= m && p[j + 1] == '*') continue;
                
                // 对应了 p[j] 为普通字符和 '.' 的两种情况
                if (i - 1 >= 0 && p[j] != '*') {
                    f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
                } 
                
                // 对应了 p[j] 为 '*' 的情况
                else if (p[j] == '*') {
                    f[i][j] = (j - 2 >= 0 && f[i][j - 2]) || (i - 1 >= 0 && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.'));
                }
            }
        }
        return f[n][m];
    }
}

参考答案:添加链接描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值