力扣第四十四题-通配符匹配

660 阅读3分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

前言

力扣第四十四题 通配符匹配 如下所示:

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

一、思路

tips:这一题和 力扣第十题-正则表达式匹配 很像,有兴趣的可以看一下那一题

很明显也可以使用 动态规划 来实现,所以第一步我们要确定 状态转移方程

状态转移方程 第一步就是确定边界情况,很显然有以下几种情况:

变量说明 dp[i][j]:表示字符 si 个字符是否可以可 p 中前 j 个字符可以匹配。(下标从 [1, 1] 开始)

  1. p[j] 为字母:dp[i][j] = (s[i] == s[j] && dp[i-1][j-1])
  2. p[j]?dp[i][j] = dp[i-1][j-1]
  3. p[j]*dp[i][j] = (dp[i][j-1] || dp[i-1][j])。(可看下面的详细解释)

解释上面的第三点:

如果 p[j] == '*' 会存在用 * 和不用 * 的两种情况,举了两个例子如下所示:

  1. s = abcdp = abcd*。此时dp[4][5] 就不需要使用 *
  2. s = abcdep = abcd*。此时dp[4][5] 就需要使用 *

举个例子

此处以 s = adcebp = *a*b 作为例子。(动态规划就像是一个填格子的游戏,从左上角开始,一直往右下的方式填写)

image.png

  1. 因为 p[0] = '*',说明以 p[0] 开始是可以匹配的,所以需要将 dp[0][1] 置为 true
  2. i=1, j=1,此时 p[0] = '*',根据 状态转移方程 可得 dp[1][1] = dp[1][0] || dp[0][1] = true
  3. i=1, j=2,此时 p[1] = 'a',根据 状态转移方程 可得 dp[1][2] = dp[0][1] = true
  4. i=1, j=3,此时 p[2] = '*',根据 状态转移方程 可得 dp[1][3] = dp[1][2] || dp[0][3] = true
  5. i=1, j=4,此时 p[3] = 'b',此时无法匹配,故 dp[1][4] = false
  6. 后续的遍历基本类似,故不一一列举
  7. 最终可以得到 dp[5][4] = true,故返回结果 true 即可

填完的表格如下所示:

image.png

二、实现

实现代码

实现代码与思路基本保持一致

    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
        dp[0][0] = true;
        // 处理p中的前N个 * ,并记录有多少个*
        int count = 1;
        for (int i = 1; i <= n; ++i) {
            if (p.charAt(i - 1) == '*') {
                dp[0][i] = true;
                count++;
            } else {
                break;
            }
        }
        // 往右下走
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++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[m][n];
    }

测试代码

    public static void main(String[] args) {
        new Number44().isMatch("adceb", "*a*b");
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥