19.正则表达式匹配

19. 正则表达式匹配

1 题目描述

​ 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

2 题目分析

​ 假设主串为 A,模式串为 B 从最后一步出发,需要关注最后进来的字符。假设 A 的长度为 n ,B 的长度为 m ,关注正则表达式 B 的最后一个字符是谁,它有三种可能,正常字符、* 和 .(点),那针对这三种情况讨论即可,如下:

  1. 如果 B 的最后一个字符是正常字符,那就是看 A[n-1] 是否等于 B[m-1],相等则看 A_{0…n-2}与 B_{0…m-2},不等则是不能匹配,这就是子问题。

  2. 如果 B 的最后一个字符是.,它能匹配任意字符,直接看 A{0…n-2}与 B{0…m-2}

  3. 如果 B 的最后一个字符是*它代表 B[m-2]=c 可以重复0次或多次,它们是一个整体 c∗

  • 情况一:A[n-1]是 0 个 c,B 最后两个字符废了,能否匹配取决于 A_{0…n-1}和 B_{0…m-3}是否匹配

  • 情况二:A[n-1] 是多个 c中的最后一个(这种情况必须 A[n-1]=c或者 c=’.’),所以 A 匹配完往前挪一个,B继续匹配,因为可以匹配多个,继续看 A{0…n-2}和 B{0…m-1}是否匹配。

转移方程

f[i] [j]代表 A 的前 i个和 B 的前 j 个能否匹配

对于前面两个情况,可以合并成一种情况 f[i] [j] = f[i-1] [j-1]

对于第三种情况,对于 c*分为看和不看两种情况

不看:直接砍掉正则串的后面两个, f[i] [j] = f[i] [j-2]
看:正则串不动,主串前移一个,f[i] [j] = f[i-1] [j]

初始条件
特判:需要考虑空串空正则

  • 空串和空正则是匹配的,f[0] [0] = true

  • 空串和非空正则,不能直接定义 true 和 false,必须要计算出来。(比如A= ‘’ ‘’ ,B=a* b *c *)

  • 非空串和空正则必不匹配,f[1] [0]=…=f[n] [0]=false

  • 非空串和非空正则,那肯定是需要计算的了。

大体上可以分为空正则和非空正则两种,空正则也是比较好处理的,对非空正则我们肯定需要计算,非空正则的三种情况,前面两种可以合并到一起讨论,第三种情况是单独一种,那么也就是分为当前位置是 * 和不是 *两种情况了。

作者:jerry_nju

3 代码

class Solution {
    public boolean isMatch(String A, String B) {
        int n = A.length();
        int m = B.length();
        boolean[][] f = new boolean[n + 1][m + 1];

        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.charAt(j - 1) != '*') {
                        if (i > 0 && (A.charAt(i - 1) == B.charAt(j - 1) || B.charAt(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.charAt(i - 1) == B.charAt(j - 2) || B.charAt(j - 2) == '.')) {
                            f[i][j] |= f[i - 1][j];
                        }
                    }
                }
            }
        }
        return f[n][m];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值