《剑指offer》-正则表达式匹配

本文深入解析了正则表达式匹配算法,详细阐述了如何处理包含‘.‘和‘*‘的正则表达式,通过递归方式实现字符串与模式的完全匹配,探讨了‘*‘符的三种匹配情况,提供了完整的Java代码实现及测试用例。

正则表达式匹配

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

每次从字符串中拿出一个字符和模式中的字符来匹配,相对而言,模式中的第二个字符不是 ’ * ’ 的时候,比较简单,直接进行比较即可。
如果第二个字符是 ’ * ‘,那么有三种情况,分别表示,’ * ’ 只匹配 一次、匹配 0 次、匹配多次

  1. 在模式上向后移动两位,在字符串上向后移动一位。这种情况表示,两者只匹配一次,
  2. 在模式上向后移动两位,在字符串不移动。这种情况表示,模式上的不匹配,即包含 0 次
  3. 在模式上不移动,在字符串上向后移动一位。这种情况表示,模式上匹配多次。

这里解释一下,在 matchCore 中,不进行 str.length == strCur && pattern.length != patCur 的判断。因为即使 strCur 到头了,pattern 后面也依然可以有字符。

贴一个比较好的分析
首先,考虑特殊情况:

  1. 两个字符串都为空,返回true
  2. 当第一个字符串不空,而第二个字符串空了,返回false(因为这样,就无法匹配成功了,而如果第一个字符串空了,第二个字符串非空,还是可能匹配成功的,比如第二个字符串是" a * a * a * a ", 由于 ’ * '之前的元素可以出现0次,所以有可能匹配成功)
  3. 之后就开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern下一个字符可能是’ * ‘, 这里我们分两种情况讨论:pattern下一个字符为’ * ‘或不为’ * ':
    1. pattern下一个字符不为’ * ‘:这种情况比较简单,直接匹配当前字符。如果匹配成功,继续匹配下一个;如果匹配失败,直接返回false。注意这里的“匹配成功”,除了两个字符相同的情况外,还有一种情况,就是pattern的 当前字符为’ . ‘,同时str的当前字符不为‘\0’
    2. pattern下一个字符为 ’ * '时,稍微复杂一些,因为 ’ * '可以代表0个或多个。这里把这些情况都考虑到:
      1. ’ * '匹配0个字符时,str当前字符不变,pattern当前字符后移两位,跳过这个 ’ * '符号;
      2. 当’ * '匹配1个,str当前字符移向下一个,pattern当前字符后移两位
      3. 当’ * '匹配多个时,str当前字符移向下一个,pattern当前字符不变。
public class Solution {
    public boolean match(char[] str, char[] pattern){
        if(str == null || pattern == null){
            return false;
        }
        return matchCore(str, pattern, 0, 0);
    }
    
    public boolean matchCore(char[] str, char[] pattern, int strCur, int patCur){
        % 判断两者是否都到了末尾,是的话,则匹配成功
        if(str.length == strCur && pattern.length == patCur){
            return true;
        }
        % 判断字符串没有到末尾,模式到末尾,则匹配失败
        if(str.length != strCur && pattern.length == patCur){
            return false;
        }
        % 如果模式的下一个字符是 ' * ' 且 没有超出界限
        if(patCur + 1 < pattern.length && pattern[patCur + 1] == '*'){
            % 判断模式的当前字符是否和字符串的字符匹配 或者 模式的字符是 ' . ' 这两种情况都算匹配成功
            if((strCur != str.length && pattern[patCur] == str[strCur]) || (pattern[patCur] == '.' && str.length != strCur)){
                % 3个或,第一个是匹配一次、第二个是匹配多次、第三个是匹配0return matchCore(str, pattern, strCur+1, patCur+2) ||
                    matchCore(str, pattern, strCur+1, patCur) ||
                    matchCore(str, pattern, strCur, patCur+2);
            }else {
                % 如果模式的当前字符和字符串的字符匹配失败。这种情况不是返回false,而是认为匹配0return matchCore(str, pattern, strCur, patCur+2);
            }
        }
        % 如果模式的下一个字符不是' * ' ,则按照正常一一匹配
        if((strCur != str.length && str[strCur] == pattern[patCur]) || (pattern[patCur] == '.' && str.length != strCur)){
            return matchCore(str, pattern, strCur+1, patCur+1);
        }
        return false;
    }
}

测试用例
功能测试:模式字符串李包含普通字符、 ’ * ’ 、’ . ’ 、模式字符串和输入字符串匹配、不匹配
特殊输入测试:输入字符串和模式字符串都为 null、空字符串;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值