通配符匹配

1,325 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

一、题目

LeetCode 通配符匹配

给定一个字符串 (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'

二、题解

给定有两个字符串,看两个字符串是否完全匹配得上。可以说字符串s就是匹配字符串,字符串p就是待匹配字符串,要用字符串p去匹配字符串s,字符串p中可能存在的?*字符可以相应的抵消字符串s的某些字符来使得两个字符串能够匹配(不一定是要两个字符串的字符完全相等)。

方法一 根据题意,字符串s中只会存在小写字母或者为空,而字符串p同样可能为空或者只存在小写字母以及匹配字符?*。而?字符可以匹配任意一个字符,*字符可以匹配空字符串或者任意的字符串,也就是可以匹配多个连续的字符。对此可以使用动态规划来枚举匹配,定义一个dp数组,用dp[i][j]表示字符串s的前i个字符与字符串p的前j个字符是否匹配。初始的对于两个字符串都是空的时也能匹配得了即dp[0][0] = true。然后遍历两个字符串的字符来枚举匹配,对于字符串p的字符如果是小写字母的话,那么字符串s中也得是对应的字母才能匹配的上;如果是?字符的话字符串s可以的任意的字母即dp[i][j] = dp[i - 1][j - 1];如果是*字符的话字符串s也可以是任意的字符或者是多个字符即dp[i][j] = dp[i][j - 1] || dp[i - 1][j]。当遍历结束的时候返回最后计算的结果即可。

三、代码

方法一 Java代码

class Solution {
    public boolean isMatch(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();
        boolean[][] dp = new boolean[sLen + 1][pLen + 1];
        dp[0][0] = true;
        for (int i = 1; i <= pLen; i++) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = true;
            } else {
                break;
            }
        }
        for (int i = 1; i <= sLen; ++i) {
            for (int j = 1; j <= pLen; ++j) {
                if (p.charAt(j - 1) == '*') {
                    dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
                } else if (p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
        return dp[sLen][pLen];
    }
}

时间复杂度:O(n^2),需要遍历两个字符串的字符。

空间复杂度:O(n^2),动态规划需要一个dp数组。