【剑指Offer】面试题19:正则表达式匹配

本文介绍了一种基于递归的正则表达式匹配方法,能够处理包含'.'和'*'的模式。通过实例解析了如何针对'*'的三种可能情况进行匹配,并提供了完整的Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


这道题的难点非常明显,那就是要处理 '*' 这个字符的情况,当我们遇到 '*' 时,可能会碰到以下三种情况

  • 忽略 '*' 和它前面的字符,也就是题目中说的出现 0 次的情况,直接从下一个字符开始匹配。
  • 如果 '*' 前面的字符和字符串当前的字符相匹配,那么我们选择将字符串后面的字符和 '*' 继续进行匹配。
  • 如果 '*' 前面的字符和字符串当前的字符相匹配,我们还可以选择只匹配这一次的 '*',后面不继续进行匹配。

我们假设匹配字符串为 "ab*d",上面 3 种情况的有限状态机示意图如下所示:

在这里插入图片描述
对于字符 b,我们可以选择直接跳过去匹配下一个字符 d(对应第 1 点),也可以选择匹配一次之后接着匹配字符 d(对应第 3 点),或者在匹配之后继续匹配字符 b(对应第 2 点)。


而对于上面有多种处理 '*' 字符的情况,最简便的方法明显是使用递归的方式进行处理,就像走迷宫问题一样,把所有的情况都试过一遍,我们就知道字符串到底能不能匹配正则表达式了,实现代码如下:

public class Test {
    public static void main(String[] args) {
        System.out.println(match("aaaab", "a*.b"));
    }

    public static boolean match(String str, String pattern){
        if (str.length() == 0 && pattern.length() == 0){
            return true;
        }
        if (str.length() == 0 || pattern.length() == 0){
            return false;
        }
        return matchCore(str, pattern, 0, 0);
    }

    private static boolean matchCore(String str, String pattern, int i, int j) {
        // 字符串和正则表达式均已匹配到最后一个字符,说明匹配成功
        if (i == str.length() && j == pattern.length()){
            return true;
        }
        // 当正则表达式无字符可继续匹配时而字符串还未匹配完,匹配失败
        if (i != str.length() && j == pattern.length()){
            return false;
        }

        // 处理 '*' 的情况
        if (j < pattern.length()-1 && pattern.charAt(j+1) == '*'){
            // '*' 前的字符与字符串当前字符相等
            if (pattern.charAt(j) == str.charAt(i)){
                        // 直接跳过,不进行匹配
                return matchCore(str, pattern, i, j+2) ||
                        // 匹配一次后跳过
                        matchCore(str, pattern, i+1, j+2) ||
                        // 匹配一次后继续进行匹配
                        matchCore(str, pattern, i+1, j);
            } else {
                // 直接跳过,不进行匹配
                return matchCore(str, pattern, i, j+2);
            }
        }

        // 处理普通字符以及 '.' 的情况
        if (pattern.charAt(j) == str.charAt(i) || pattern.charAt(j) == '.'){
            return matchCore(str, pattern, i+1, j+1);
        }

        return false;
    }
}

这段代码结合前面的分析看并不复杂,其中的 i、j 表示分布指向 str(字符串)和 pattern(正则表达式)所在位置的指针。


参考

该题目以及解题思路源于:

  • 《剑指Offer》第二版
    • 第 3 章 高质量的代码
      • 3.3 代码的完整性
        • 面试题19:正则表达式匹配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值