leetcode:44. 通配符匹配

题目

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

  1. '?' 可以匹配任何单个字符。
  2. '*' 可以匹配任意字符串(包括空字符串)。

两个字符串完全匹配才算匹配成功。
说明:

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

示例:

  1. 输入:
  2. s = "aa"
  3. p = "a"
  4. 输出: false
  5. 解释: "a" 无法匹配 "aa" 整个字符串。
  1. 输入:
  2. s = "aa"
  3. p = "*"
  4. 输出: true
  5. 解释: '*' 可以匹配任意字符串。
输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
输入:
s = "adceb"
p = "*a*b"
输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
输入:
s = "acdcb"
p = "a*c?b"
输出: false

解答 & 代码

二维动态规划:

  • 动态规划数组 **dp**dp[i][j] 代表字符串 s 的前 i 个字符 s[0,...,i-1] 和字符模式 p 的前 j 个字符 p[0,...,j-1] 是否匹配
  • 状态转移方程
    • 如果 p[j - 1] = '*',则 dp[i][j] = dp[i][j - 1] || dp[i - 1][j - 1] || dp[i - 1][j]
      • dp[i][j - 1] 代表 '*' 匹配 0 个字符,因此消去 '*'p[j-1]
      • dp[i - 1][j - 1] 代表 '*' 匹配 1 个字符,因此消去 s[i-1]p[j-1]
      • dp[i - 1][j] 代表 '*' 匹配 n 个字符(n > 1),因此消去 s[i-1],保留 p[j-1]'*' 继续匹配
    • 否则,p[j - 1] 不是 '*'dp[i][j] = dp[i - 1][j - 1] && match(s[i - 1], p[j - 1])
      • 也就是看 s[i-1]p[j-1] 是否匹配,以及消去 s[i-1]p[j-1] 后剩余部分是否匹配
  • 初始化

    • dp[0][0] = truesp 都为空串时匹配
    • dp[0][j] = dp[0][j - 1] && p[j - 1] == '*'s 为空串,p 不为空,若想匹配,则 p 只能全为 '*'
    • dp[i][0] = falses 不为空串,而 p 为空串,则不可能匹配

      class Solution {
      private:
      bool match(char a, char b)
      {
         return a == b || b == '?';
      }
      public:
      bool isMatch(string s, string p) {
         int sLen = s.size();
         int pLen = p.size();
         // 动态规划数组 dp:dp[i][j] 代表字符串 s 的前 i 个字符 s[0,...,i-1] 和
         // 字符模式 p 的前 j 个字符 p[0,...,j-1] 是否匹配
         vector<vector<bool>> dp(sLen + 1, vector<bool>(pLen + 1));
      
         // 初始化
         dp[0][0] = true;
         for(int j = 1; j <= pLen; ++j)
             dp[0][j] = dp[0][j - 1] && p[j - 1] == '*';
         for(int i = 1; i <= sLen; ++i)
             dp[i][0] = false;
      
         // 状态转移
         for(int i = 1; i <= sLen; ++i)
         {
             for(int j = 1; j <= pLen; ++j)
             {
                 if(p[j - 1] == '*')
                     dp[i][j] = dp[i][j - 1] ||             // * 匹配 0 次
                                 dp[i - 1][j - 1] ||        // * 匹配 1 次
                                 dp[i - 1][j];            // * 匹配 n 次
                 else
                     dp[i][j] = dp[i - 1][j - 1] && match(s[i - 1], p[j - 1]);
             }
         }
         return dp[sLen][pLen];
      }
      };
      

      复杂度分析:设字符串 s 长为 N,字符模式 p 长为 M

  • 时间复杂度 O(NM):

  • 空间复杂度 O(NM):

执行结果:

执行结果:通过

执行用时:88 ms, 在所有 C++ 提交中击败了 23.55% 的用户
内存消耗:11 MB, 在所有 C++ 提交中击败了 68.60% 的用户

类似题目

[困难] 10. 正则表达式匹配