当前位置 : 首页 » 文章分类 :  算法  »  LeetCode.010.Regular Expression Matching 正则表达式匹配

LeetCode.010.Regular Expression Matching 正则表达式匹配

题目描述

10 Regular Expression Matching
https://leetcode-cn.com/problems/regular-expression-matching/

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

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

示例 5:

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

相似题目

LeetCode.010.Regular Expression Matching 正则表达式匹配
LeetCode.044.Wildcard Matching 通配符匹配


解题过程

dp[i][j] 表示 s 前 i 个字符和 p 前 j 个字符是否匹配,即 s[0...i-1]p[0...j-1] 是否匹配
dp[0][0] = true 即空串和空串是匹配的,dp[s.length][p.length] 就是最终结果

1、当 p 的第 j 个字符不是 * 时,和 s 的第 i 个字符比较,相等则 dp[i][j] = dp[i-1][j-1],不等则 dp[i][j] = false
2、当 p 的第 j 个字符是 * 时,看第 p 的第 j-1 个字符,和 s 的第 i 个字符比较:
(1) 如果不等,没关系,我们可以选择不使用 p[j-1]* 这个模式(因为 * 表示重复 0 次或多次),则 dp[i][j] = dp[i][j-2]
(2) 如果相等,可以有两个选择,继续和 s 的前一个字符比较(模式重复多次),或者还是可以选择不使用 p[j-1]* 这个模式(重复 0 次),则 dp[i][j] = dp[i-1][j] || dp[i][j-2]

其中判断两个字符是否匹配时,如果 p 的字符是通配符 .,则可以和 s 中任意字符匹配。

时间复杂度 O(mn),空间复杂度 O(mn)

private static class SolutionV202006 {
    public boolean isMatch(String s, String p) {
        // dp[i][j] 表示 s 前 i 个字符和 p 前 j 个字符是否匹配,即 s[0...i-1] 和 p[0...j-1] 是否匹配
        // 则 dp[0][0] = true, dp[s.length][p.length] 就是最终结果
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1]; // 默认都是 false
        dp[0][0] = true;

        // 遍历填表
        for (int i = 0; i <= s.length(); i++) {
            for (int j = 1; j <= p.length(); j++) {
                if (j > 0 && p.charAt(j - 1) == '*') {
                    // s[i-1] 和 p[j-2] 匹配时, dp[i][j] = dp[i-1][j](和s前一个字符比较) || dp[i][j-2] (不使用当前的 x* 模式)
                    if (i > 0 && match(s.charAt(i - 1), p.charAt(j - 2))) {
                        dp[i][j] = dp[i - 1][j] || dp[i][j - 2];
                    } else {
                        // s[i-1] 和 p[j-2] 不匹配时,dp[i][j] = dp[i][j-2],即不使用当前的 x* 模式
                        dp[i][j] = dp[i][j - 2];
                    }
                } else {
                    if (i > 0 && match(s.charAt(i - 1), p.charAt(j - 1))) {
                        // s[i-1] 和 p[j-1] 匹配时, dp[i][j] = dp[i-1][j-1];否则 dp[i][j] = false
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                }
            }
        }
        return dp[s.length()][p.length()];
    }

    // 判断字符 s 和 p 是否匹配
    private boolean match(char s, char p) {
        return p == '.' || p == s;
    }
}

GitHub代码

algorithms/leetcode/leetcode/_010_RegularExpressionMatching.java
https://github.com/masikkk/algorithms/blob/master/leetcode/leetcode/_010_RegularExpressionMatching.java


上一篇 LeetCode.程序员面试金典.1618.Pattern Matching 模式匹配

下一篇 LeetCode.125.Valid Palindrome 验证回文串

阅读
评论
929
阅读预计4分钟
创建日期 2020-06-20
修改日期 2020-06-20
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论