【剑指Offer】52.正则表达式

题目描述

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

方法一:递归

自顶向下:
假设主串为s,长度为sn,模式串为p,长度为pn,位于模式串p当前的第i位来说,有‘正常字符’、‘*’、‘.’三种情况。

  • 如果p[i]为正常字符,那么我们看s[i]是否等于p[i],如果相等,说明第i位匹配成功,接下来看s[i+1…sn+1]和p[i+1…pn+1]
  • 如果p[i]为‘.’,它能匹配任意字符,直接看s[i+1…sn+1]和p[i+1…pn+1]
  • 如果p[i]为’*’,表明p[i-1]可以重复0次或者多次,需要把p[i-1]和p[i]看成一个整体。
    • 如果p[i-1]重复0次,则直接看s[i…sn-1]和p[i+2…pn-1]
    • 如果p[i-1]重复1次或多次,则直接看s[i+1…sn-1]和p[i…pn-1], 但是有个前提:s[i]= = p[i]或者p[i]= = ‘.’
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      那么可以递归进行计算:
      递归三部曲:
  • 递归函数功能:match(s, p) -> bool,表示p是否可以匹配s
  • 递归终止条件:
    • 如果s和p同时为空,表明正确匹配
    • 如果s不为空,p为空,表明不能正确匹配
    • 如果s为空,p不为空,需要计算,不能直接给出结果。
  • 下一步递归:
    • 对于前面讨论的情况1,2进行合并,如果 s==p || p == ‘.’,则match(s+1,p+1);
    • 对于情况3,如果重复一次或者多次,则match(s+1, p),如果重复0次,则match(s, p+2);

方法二:动态规划

动态规划,自底向上

  • 动态规划转移方程: f[i][j]表示s的前i个P的前j个能匹配。
  • 对于方法一的1,2两种情况可知,f[i][j] = f[i-1][j-1]
  • 如果p[i]为正常字符,那么我们看s[i]是否等于p[i],如果相等,说明第i位匹配成功,接下来看s[i+1…sn+1]和p[i+1…pn+1]
  • 如果p[i]为‘.’,它能匹配任意字符,直接看s[i+1…sn+1]和p[i+1…pn+1]
  • 对于第3种情况可知:
    • 如果重复0次,f[i][j] = f[i][j-2]
    • 如果重复1次或多次,f[i][j] = f[i-1]f[j]
  • 动态规划初始条件:
    • s为空且p为空,为真:f[0][0] = 1
    • s不为空且p为空,为假:f[1…sn][0] = 0
    public boolean match(char[] A, char[] B){
        int n = A.length;
        int m = B.length;
        boolean[][] f = new boolean[n + 1][m + 1];
        if(n==0 && m==0) return true;
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                //分成空正则和非空正则两种
                if (j == 0) {
                    f[i][j] = i == 0;
                } else {
                    //非空正则分为两种情况 * 和 非*
                    if (B[j - 1] != '*') {
                        if (i > 0 && (A[i - 1] == B[j - 1] || B[j - 1] == '.')) {
                            f[i][j] = f[i - 1][j - 1];
                        }
                    } else {
                        //碰到 * 了,分为看和不看两种情况
                        //不看
                        if (j >= 2) {
                            f[i][j] |= f[i][j - 2];
                        }
                        //看
                        if (i >= 1 && j >= 2 && (A[i - 1] == B[j-2] || B[j-2] == '.')) {
                            f[i][j] |= f[i - 1][j];
                        }
                    }
                }
            }
        }
        return f[n][m];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值