题目描述
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。


  解法有很多,有非递归的写法,动态规划以及递归,感觉这个题属于难题了,能做出来即可,难度高还追求多种解法不是本菜鸟的风格。嗯,所以我选择在看懂递归代码后,做个总结。
代码思路:
  首先肯定是两个指针,一个在给定字符串上动,一个在模板上动。如果匹配肯定都向后移动,但此时由于有两个特殊符号捣乱,因此比较特殊。
  首先分析'.'的情况。当我们比较两个指针指的字符时,模板的字符是'.',那么可以让两个指针同时后移。这个情况简单,就默认相等嘛。换句话说,本题只用考虑有没有'*'就可以了。


  考虑'*'的相关情况情况。我们比较两个指针的字符时,如果字符串是s指针,模板是P指针指向某个字符。那么P的下一个字符不是'*'时,那么就是最普通的情况,直接都往后移一位。即s++,p++。
  分析此时有'*'时,注意此时,p+1指向了一个'*'。那么我们怎么移动指针呢。

  • 方式1:出现了'*',而且s和p指向的都不相等,就相当于模板中'*'前面的出现了0次,此时必须让p指针向后移动2位,让模板跳过'*'即可。(对于abge和ac*mn,s指b,p指c,则让p指向m,即p+2。认为c没出现过)
  • 方式2:出现了'*',而且s和p指向的相等(这里的相等可以是真正的相等,也可以是'.'标记的相等)。比如abcd和ab*cf,其中s和p都指向了b。此时应该s+1和p+2。比如abbcd和ab*cf,其中s和p都指向了b。由于b出现了多次,应该不着急移动p,所以此时s+1即可。比如"cba","cb*a*a",我也可以认为,p指向的第1个a没出现过,即使你相等。因此此时可以s不动,p+2。

  可以看到,方式2中其实又分为3种情况,而实际上,我们无法区分具体应该选择哪一个方式处理,所以只能将3个方法同时利用或运算并列起来。其中方式2的第3种处理很不容易想到,因为就算相等了,我还是认为你不相等,忽略你,是真的牛。
  再次捋一遍。由于把真正的相等和'.'标记的相等并成一类,就只用考虑'*'。如果不出现星号,就常规比较,常规比较肯定出现相等或者不等两类。如果出现星号,就考虑两个指针指的是否相等,不等,则p指针直接+2。两个指针相等,则有3种情况并列处理。再在这些判断中,加入对应边界条件,就可以很容易理解并写出代码了。

public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        if (str == null || pattern == null)
            return false;
        return matchCore(str, 0, pattern, 0);
    }
    private boolean matchCore(char[] str, int s, char[] pattern, int p) {
        //下面4行是递归结束标志,两个指针都指到了最后,才是匹配,否则不匹配
        if (s == str.length && p == pattern.length)
            return true;
        if (s < str.length && p == pattern.length)
            return false;

        //虽然比的是P位置的,但是P后面出现*时,规则需要改变。
        if (p + 1 < pattern.length && pattern[p + 1] == '*') {
            //出现了*,并且s和P指向的相同,3种情况并列
            if ((s < str.length && pattern[p] == '.')
                    || (s < str.length && pattern[p] == str[s])) {
                return matchCore(str, s, pattern, p + 2)
                        || matchCore(str, s + 1, pattern, p)
                        || matchCore(str, s + 1, pattern, p + 2);
            } else {//出现了*,并且s和p指向的不同,那就把*前面的字符理解出现了0次,p+2
                return matchCore(str, s, pattern, p + 2);
            }
        }
        //说明P后面不是*,那么就进行常规判断。相同就分别给指针+1
        if (s < str.length && (pattern[p] == str[s] || pattern[p] == '.'))
            return matchCore(str, s + 1, pattern, p + 1);
        //p后面又不是*,也没有.给你撑腰,你还敢出现不同,那必然false
        return false;
    }
}