44. 通配符匹配

610 阅读2分钟

题目介绍

力扣44题:leetcode-cn.com/problems/wi…

image.png

image.png

分析

解题思路跟 正则表达式匹配 一样。 这就是一个做「选择」的问题,要把所有可能的选择都穷举一遍才能得出结果。动态规划算法的核心就是「状态」和「选择」,「状态」无非就是ij两个指针的位置,「选择」就是p[j]选择匹配几个字符

根据「状态」,我们可以定义一个dp函数:

bool dp(string& s, int i, string& p, int j);

dp函数的定义如下:

dp(s,i,p,j) = true,则表示s[i..]可以匹配p[j..];若dp(s,i,p,j) = false,则表示s[i..]无法匹配p[j..]

p[j]*通配符时,我们分情况讨论下

  • 如果此时*p的最后一个字符,那说明直接可以完全匹配,因为*号可以匹配任意字符串
  • 否则 我们可以匹配一个字符,即dp(s, i + 1, p, j + 1),或者匹配空字符串,即 dp(s, i, p, j + 1),又或者继续往下匹配,即dp(s, i + 1, p, j)

代码如下:

class Solution {
    
    public static boolean isMatch(String s, String p) {
        return dp(s, 0, p, 0);
    }

    public static boolean dp(String s, int i, String p, int j) {
        int m = s.length();
        int n = p.length();
        if (n == j) {
            return i == m;
        }
        if (i == m) {
            //ab 2
            //ab ***
            for (; j < n; j += 1) {
                if (p.charAt(j) != '*') {
                    return false;
                }
            }
            return true;

        }
        // 记录状态 (i, j),消除重叠子问题
        String key = i + "," + j;
        if (memo.containsKey(key)) {
            return memo.get(key);
        }

        boolean res = false;
        if (s.charAt(i) == p.charAt(j) || p.charAt(j) == '?' || p.charAt(j) == '*') {
            if (p.charAt(j) == '*') {
                //s = cb p = cb* 类似于这种 * 号后面没有了
                if (j == p.length() - 1) {
                    res = true;
                } else {
                    //*可以匹配一个字符,空字符,或者继续往下匹配
                    res = dp(s, i + 1, p, j + 1) || dp(s, i, p, j + 1) || dp(s, i + 1, p, j);
                }
            } else {
                res = dp(s, i + 1, p, j + 1);
            }
        } else {
            res = false;
        }
        // 将当前结果记入备忘录
        memo.put(key, res);
        return res;
    }
}