# 1. 题目

44:通配符匹配

给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符序列(包括空字符序列)。
判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。


示例 1:

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

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

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


提示:

0 <= s.length, p.length <= 2000
s 仅由小写英文字母组成
p 仅由小写英文字母、'?' 或 '*' 组成

2. 题目分析

  1. 该题是10.正则表达式匹配的变型
  2. 也是使用动态规划方程来解决的经典题型

3. 思路分析

3.1 定义状态

使用二维数组表示状态:

dp[i][j]

图示:
在这里插入图片描述

举例

s = "aaaa"
p = "aa?*"
bp[2][2] : 表示sub_s("aa")和sub_p("aa")是否匹配

3.2 状态转移方程dp[i][j] = ?

  1. p[j-1] == 小写字母
    • 当sub_s和sub_p的最后一个字母相同的时候dp[i][j] = dp[i-1][j-1];
    • 当sub_s和sub_p的最后一个字母相同的时候dp[i][j] =false;
  2. p[j-1] == '?'
    • dp[i][j] = dp[i-1][j-1];
  3. p[j-1] == '*'
    • 当’*'匹配0个字符的时候dp[i][j] = dp[i][j-1];
    • 当’*'匹配0个字符的时候dp[i][j] = dp[i-1][j-1];
    • 当’*'匹配0个字符的时候dp[i][j] = dp[i-2][j-1];

    • 对于3,等价于
    • dp[i][j] = dp[i][j-1] || dp[i-1][j-1] || dp[i-1][j-1] || ...;
      重要的变型:(数学方法)
      上述等式令i= i-1,可得:dp[i-1][j] = dp[i-1][j-1] || dp[i-1][j-1] || dp[i-2][j-1]...;
      将两式共同部分消除可得:
    • dp[i][j] = dp[i][j-1] || dp[i-1][j];

3.3 边界条件(初始化条件)

根据状态转移方程i,j都是从小到大递增的,因此需要明确三个边界条件:

dp[0][0] 
dp[i][0]
dp[0][j]
  1. dp[0][0] = true;
  2. dp[i][0] = false; ( i > 0)
  3. 分情况:
    • p[j] == '*'时, dp[0][j] = dp[0][j-1]; j > 0
      • p[j] == '*'时, dp[0][j] = false;

4. 解题代码

4.1 初始化:

class Solution {
public:
    bool isMatch(string s, string p) {
        // 状态转移方程
        int size_s = s.size();
        int size_p = p.size();
        std::vector<std::vector<bool>> bp(size_s + 1, std::vector<bool>(size_p + 1, false));
        bp[0][0] = true;

        for (int idx = 1; idx < size_p + 1; ++idx) {
            bp[0][idx] = (p[idx - 1] == '*') && (bp[0][idx - 1]);
        }
        ...
    }
};

4.2 循环求解动态转移数组

class Solution {
public:
    bool isMatch(string s, string p) {
        ...
        for (int i = 1; i < size_s + 1; ++i) {
            for (int j = 1; j < size_p + 1; ++j) {
                if (p[j - 1] != '*') {
                    if (p[j - 1] == '?' || p[j - 1] == s[i - 1]) {
                        bp[i][j] = bp[i - 1][j - 1];
                    }
                } else {
                    bp[i][j] = (bp[i][j - 1] || bp[i - 1][j]);
                }
            }
        }

        return bp[size_s][size_p];
    }
};

注:虽然通过了,但是细节待完善,代码只做思路提示,欢迎评论区讨论。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐