Regular Expression Matching

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true

isMatch("aab", "c*a*b") → true


使用递归。

对于 pattern p, indexP 对应当前访问的 char, indexP + 1 对应下一个 char. 


case 1 :  if (p.charAt(indexP + 1) != '*')

如果下一个 char (char at indexP + 1) 不是 ‘*’, 即 if (p.charAt(indexP + 1) != '*'), 那么必须要求当前的 char at indexP 和 char at indexS 是对应的。

例如: s: ......   a        b......

             p: ......   c ......

                           pp+1

这里 index p+1 的位置, char != '*' , 那么如果 在 index p 的位置上不对应, 则直接返回 false, 因为到这一层 p之前的部分匹配成功,但到p 的位置,匹配已经失败了,而且 p + 1 不是 ‘*’, 没法跳过 p。

例如: s:  ......  b  ......

             p: ...... ac  ......

p p+1

在这个例子中,p 的位置对应的 char 是一样的,匹配成功,那么就进入下一层递归调用matchHelper(s, p, indexS + 1, indexP + 1)。

至于 p + 1 位置上的 b 和 c 不对应,那是下一层递归的任务,当进入下一层后,原来的 p + 1 就变成了 p。



case 2 :  if (p.charAt(indexP + 1) == '*')

第二种情况是,当下一个 char 是 ‘*’ 时。

此时意味着当前index 对应的 char 可以出现0次或者多次。

但是到底是匹配几个才是最后成功匹配的个数呢?

例如:

s:     a ab

p:  a * b

用 * 匹配了三个。

s:     a ab

p:  a * a b

用 * 匹配了两个个。

在没有进行后续部分的比较前,没法确定到底应该用 * 匹配几个,才是应该使用的正确个数。因此方法就是把所有可能匹配上的个数都试一遍。因此 从 0 ~ n 个可以用 * 匹配上 s 的后续的 char 的,都调用一次递归,如果某一种个数最后成功完成了匹配,就 return true, 否则继续用 * 匹配 s 的下一个 char.

直到 s 中 所有可以与当前 * 匹配的都匹配完,即失去与 * 的匹配后,却没有一次成功的匹配并return true. 则跳过 * (indexP + 2),继续后续的递归:

// until we get char at indexS != charAt indexP
return matchHelper(s, p, indexS, indexP + 2);

s s+1s+2s+3s+4

例子: s:  ......  a a ac ......

             p: ...... a*   ......

p p+1p + 2

这里 p + 1 是 ‘*’

循环第一次,调用 if (matchHelper(s, p, indexS, indexP + 2)) {return true;},也就是 a* 没有和 s ... s+4 的任何一个a匹配,直接跳过

循环第二次, s++, 此时indexS指在 s + 1. 也就是 a* 匹配了一个 a, 然后跳过a*, 进入后续的比较

循环第三次     s++, 此时indexS指在 s + 2. 也就是 a* 匹配了两个 a, 然后跳过a*, 进入后续的比较

...

(这期间如果有一次的组合是证明成功的,就会return true,因为在 if 里调用了递归)

最后 indexS 到 s + 4(a* 匹配了s中所有可以匹配的a), 此时说明之前的几次都没匹配成功,则继续进入后续的调用:

// until we get char at indexS != charAt indexP
return matchHelper(s, p, indexS, indexP + 2);


public boolean matchHelper(String s, String p, int indexS, int indexP) {
        // 当匹配进行到最后,s 和 p的指针超出了末尾
        if (indexP == p.length()) {
            return indexS == s.length();
        }
        
        // 当匹配进行到最后,s 和 p的指针到达了末尾,且相等
        if (indexP == p.length() - 1) {
            return indexS == s.length() - 1 
                   && (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.');
        }
        
        // next char != '*'
        // 若此时 s 和 p 匹配不上,则return false
        if (p.charAt(indexP + 1) != '*') {
            if (indexS < s.length() && (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.')) {
                return matchHelper(s, p, indexS + 1, indexP + 1); 
            } else {
                return false;
            }
        } else {
        // next char == '*'
            // 用 while loop 和 递归把所有匹配的个数都尝试一遍
            while (indexS < s.length() && (s.charAt(indexS) == p.charAt(indexP) || p.charAt(indexP) == '.')) {
                if (matchHelper(s, p, indexS, indexP + 2)) {
                    return true;
                }
                indexS++;
            }
            // until we get char at indexS != charAt indexP
            // 之前的递归调用都没有返回 true, 
            // 此时 * 匹配了当前 s 中后续所有可以匹配的重复char, 跳过 * 继续往后
            return matchHelper(s, p, indexS, indexP + 2);
        }
    }

    public boolean isMatch(String s, String p) {
        return matchHelper(s, p, 0, 0);
    }



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值