当前位置 : 首页 » 文章分类 :  算法  »  LeetCode.044.Wildcard Matching 通配符匹配

LeetCode.044.Wildcard Matching 通配符匹配

题目描述

44 Wildcard Matching
https://leetcode-cn.com/problems/wildcard-matching/

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。

‘?’ 可以匹配任何单个字符。
‘*’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。

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

示例 1:

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

示例 2:

输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。

示例 3:

输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。

示例 4:

输入:
s = "adceb"
p = "*a*b"
输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".

示例 5:

输入:
s = "acdcb"
p = "a*c?b"
输出: 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 个字符 p[j-1] 不是 * 时,如果 p[j-1]?(百搭) 或者和 s[i-1] 相等,则 dp[i][j] = dp[i-1][j-1]
2、当 p 的第 j 个字符 p[j-1]* 时,可以匹配 0 个或多个任意字符:
(1) 匹配 0 个字符时,即忽略星号,dp[i][j] = dp[i][j-1]
(2) 匹配任意字符时,不用管 s[i-1] 是什么,dp[i][j] = dp[i-1][j]

初始条件:
1、dp[0][0] = true,即 s,p 都是空串时可以匹配
2、p 为空 s 不为空时是无法匹配,java 中 boolean 数组默认值就是 false,无需初始化
3、s 为空 p 不为空时,只有当 p 全是 * 号时才能匹配

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

private static class SolutionV202007 {
    public boolean isMatch(String s, String p) {
        // dp[i][j] 表示 s 前 i 个字符组成的子串和 p 前 j 个字符组成的子串是否匹配
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
        dp[0][0] = true; // s,p 都是空串时可以匹配
        // p 为空 s 不为空时是无法匹配,boolean 数组默认值就是 false,无需初始化
        // s 为空 p 不为空时,只有当 p 全是 * 号时才能匹配
        for (int i = 1; i <= p.length(); i++) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = true;
            } else {
                break;
            }
        }

        // 遍历填表,i,j 遍历的是二维表格 dp 的下标
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= p.length(); j++) {
                if (p.charAt(j - 1) != '*') {
                    // p[j-1] 不是星号时, p[j-1]==s[i-1] 或 p[j-1]=='?' 时, dp[i][j] = dp[i-1][j-1]
                    dp[i][j] = dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?');
                } else {
                    // p[j-1] 是星号,可以匹配 0 个或多个任意字符
                    // 匹配 0 个字符时,dp[i][j] = dp[i][j-1],匹配任意字符时,dp[i][j] = dp[i-1][j]
                    dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
                }
            }
        }
        return dp[s.length()][p.length()];
    }
}

GitHub代码

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


上一篇 LeetCode.063.Unique Paths II 不同路径 II

下一篇 LeetCode.032.Longest Valid Parentheses 最长有效括号

阅读
评论
843
阅读预计4分钟
创建日期 2020-07-05
修改日期 2020-07-05
类别

页面信息

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

评论