你须要的LeeCode题No.07——“正则表达式匹配”_一点课堂(多岸学院)

正则表达式匹配

题目:正则表达式匹配java

描述:给定一个字符串 (s) 和一个字符模式 (p)。实现支持 '.' 和 '*' 的正则表达式匹配。正则表达式

  • '.' 匹配任意单个字符。
  • '*' 匹配零个或多个前面的元素。

匹配应该覆盖整个字符串 (s) ,而不是部分字符串。数组

说明:函数

  • s 可能为空,且只包含从 a-z 的小写字母。
  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

示例 1:学习

  • 输入: s = "aa", p = "a"
  • 输出: false
  • 解释: "a" 没法匹配 "aa" 整个字符串。

示例 2:code

  • 输入: s = "aa", p = "a*"
  • 输出: true
  • 解释: '*' 表明可匹配零个或多个前面的元素, 便可以匹配 'a' 。所以, 重复 'a' 一次, 字符串可变为 "aa"。

示例 3:blog

  • 输入: s = "ab", p = ".*"
  • 输出: true
  • 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。

示例 4:递归

  • 输入: s = "aab", p = "c*a*b"
  • 输出: true
  • 解释: 'c' 能够不被重复, 'a' 能够被重复一次。所以能够匹配字符串 "aab"。

示例 5:图片

  • 输入: s = "mississippi", p = "mis*is*p*."
  • 输出: false

解析

这应该是遇到的第一个困难类型的题目了。若是只有 '.' 这个字符,匹配是十分简单的,每匹配一个字符,问题就转化为在剩余的字符串中作相同的操做,例如对于字符串 s="aa", p=".a" 而言,由于第一个字符 'a' 和 '.' 相匹配,因此问题就转化成 s="a", p= "a" 是否匹配。若是咱们用函数 f(x, y) 表示字符串 s 的 前 x 位与字符串 p 的前 y 位是否匹配,那么它具备如下的表达式:ip

若是 s.charAt(x)能够匹配p.charAt(y),则 f(x, y) = f(x+1, y+1)
不然,f(x, y) = false

然而,由于 '*' 定义为能够匹配零个或多个前面的元素,这使得上述规则再也不适用,因此咱们要对它进行适当的修正。首先,'*' 必须在某个小写字母或者 '.' 以后,这就意味着咱们必须校验一个字符后边是否有 '*' 标记,若是有,字符串 s 能够与这部分不匹配,例如 s="aa", p="b*aa",虽然第一个字符 'a' 不能匹配 'b',但因为 '*' 的缘由,能够忽略这部分不一样。因此咱们有了以下策略:

记 canMatchFirst表示s.charAt(x)是否能够匹配p.charAt(y)
若是p.charAt(y+1)=='\*',f(x, y) = f(x, y+2) || (canMatchFirst && f(x+1, y))
不然和只有 '.' 时同样,f(x, y) = canMatchFirst && f(x+1, y+1)

有了思路,咱们就能够写代码了,参考以下:

public boolean isMatch(String s, String p) {
    return isMatch(s, p, s.length(), p.length(), 0, 0);
}
private boolean isMatch(String s, String p, int lenOfS, int lenOfP, int startS, int startP) {
    // 当前参与递归运算的长度
    int currLenOfS = lenOfS - startS;
    int currLenOfP = lenOfP - startP;

    if (currLenOfP == 0) {
        return currLenOfS == 0;
    }

    char pc = p.charAt(startP);
    // 第一个字符是否匹配
    boolean canMatchFirst = currLenOfS != 0 && (pc == '.' || s.charAt(startS) == pc);

    // 第二个字符是 * 的状况
    if (currLenOfP > 1 && p.charAt(startP + 1) == '*') {
        return isMatch(s, p, lenOfS, lenOfP, startS, startP + 2)
                || (canMatchFirst) && isMatch(s, p, lenOfS, lenOfP, startS + 1, startP);
    } else {
        return (canMatchFirst) && isMatch(s, p, lenOfS, lenOfP, startS + 1, startP + 1);
    }
}

总结

虽然咱们常常使用正则表达式,可是它的实现确实是十分复杂的,以上只能当作一个引子,展现了正则表达式最简单的几个状况,可是它却为咱们了解正则表达式的实现提供了思路。以上的分析思路也十分重要,在以后的不少问题中,咱们都须要这样思考。好了,接下来让咱们看一个有趣的题目吧。

下题预告

题目:盛最多水的容器

描述:给定 n 个非负整数 a1,a2,...,an,每一个数表明坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器能够容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

file 图中垂直线表明输入数组 [1,8,6,2,5,4,8,3,7]。在此状况下,容器可以容纳水(表示为蓝色部分)的最大值为 49。</div>

示例:

* 输入: [1,8,6,2,5,4,8,3,7]
* 输出: 49

相关源码请加QQ获取。


【感谢您能看完,若是可以帮到您,麻烦点个赞~】

更多经验技术欢迎前来共同窗习交流: 一点课堂-为梦想而奋斗的在线学习平台 http://www.yidiankt.com/

![关注公众号,回复“1”免费领取-【java核心知识点】] file

QQ讨论群:616683098

QQ:3184402434

想要深刻学习的同窗们能够加我QQ一块儿学习讨论~还有全套资源分享,经验探讨,等你哦! 在这里插入图片描述

相关文章
相关标签/搜索