正则表达式匹配

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

分析:这题好难理解,先把题解放在这里。

示例 1:

    输入:

    s = "aa"

    p = "a"

    输出: false

    解释: "a" 无法匹配 "aa" 整个字符串。

示例 2:

    输入:
    s = "aa"
    p = "a*"
    输出: true
    解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

    输入:
    s = "aab"
    p = "c*a*b"
    输出: true
    解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 4:

     输入:

     s = "ab"

     p = ".*"

     输出: true

     解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。

示例 5:

    输入:

    s = "mississippi"

    p = "mis*is*p*."

    输出: false

首先肯定是两个指针,一个在给定字符串上动,一个在模板上动。如果匹配肯定都向后移动,但此时由于有两个特殊符号捣乱,因此比较特殊。首先分析 '.' 的情况。当我们比较两个指针指的字符时,模板的字符是 '.',那么可以让两个指针同时后移。这个情况简单,就默认相等嘛。换句话说,本题只用考虑有没有 '*' 就可以了。考虑 '*' 的相关情况情况。我们比较两个指针的字符时,如果字符串是 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 种情况并列处理。再在这些判断中,加入对应边界条件,就可以很容易理解并写出代码了。

 

PS:目前处于不理解阶段!

 1 public class Solution {
 2     public boolean match(char[] str, char[] pattern) {
 3         if(str == null || pattern == null) {
 4             return false;
 5         }
 6         return matchCore(str, 0, pattern, 0);
 7     }
 8     private boolean matchCore(char[] str, int s, char[] pattern, int p) {
 9         //下面4行是递归结束标志,两个指针都指到了最后,才是匹配,否则不匹配
10         if(s == str.length && p == pattern.length) {
11             return true;
12         }
13         if(s < str.length && p == pattern.length) {
14             return false;
15         }
16         //虽然比的是P位置的,但是P后面出现*时,规则需要改变。
17         if(p + 1 < pattern.length && pattern[p + 1] == '*') {
18             //出现了*,并且s和P指向的相同,3种情况并列
19             if((s < str.length && pattern[p]=='.') || (s < str.length && pattern[p]==str[s])){
20                 return matchCore(str, s, pattern, p + 2)
21                         || matchCore(str, s + 1, pattern, p)
22                         || matchCore(str, s + 1, pattern, p + 2);
23             } else { //出现了*,并且s和p指向的不同,那就把*前面的字符理解出现了0次,p+2
24                 return matchCore(str, s, pattern, p + 2);
25             }
26         }
27         //说明P后面不是*,那么就进行常规判断。相同就分别给指针+1
28         if (s < str.length && (pattern[p] == str[s] || pattern[p] == '.'))
29             return matchCore(str, s + 1, pattern, p + 1);
30         //p后面又不是*,也没有.给你撑腰,你还敢出现不同,那必然false
31         return false;
32     }
33 }

 

posted on 2020-09-08 16:19  _那些你很冒险的梦  阅读(329)  评论(0)    收藏  举报

导航