Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.
  • p could be empty and contains only lowercase letters a-z, and characters like ? or *.

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = "*"
Output: true
Explanation: '*' matches any sequence.

Example 3:

Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.

Example 4:

Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".

Example 5:

Input:
s = "acdcb"
p = "a*c?b"
Output: false

通配符匹配。题意是给两个字符串S和P,其中P是带有通配符的。请你返回P是否能根据通配符的规则匹配S。其中

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

思路是动态规划。这个题也有双指针的做法但是个人感觉动态规划的做法更好记。

首先定义动态规划的方程是dp[i][j],定义是S的前i个字符和P的前j个字符是否相配。

初始化

  • dp[0][0]:什么都没有,所以为true
  • 第一行dp[0][j],换句话说,s为空,与p匹配,所以只要p开始为*才为true
  • 第一列dp[i][0],当然全部为False

转移方程

  • 如果(s[i] == p[j] || p[j] == "?") && dp[i-1][j-1] ,有dp[i][j] = true
  • 如果p[j] == "*" && (dp[i-1][j] = true || dp[i][j-1] = true) 有dp[i][j] = true

​note:

  • dp[i][j-1],表示*代表是空字符,例如ab,ab*
  • dp[i-1][j],表示*代表非空任何字符,例如abcd,ab*

时间O(mn)

空间O(mn)

Java实现

 1 class Solution {
 2     public boolean isMatch(String s, String p) {
 3         int m = s.length();
 4         int n = p.length();
 5         boolean[][] dp = new boolean[m + 1][n + 1];
 6         dp[0][0] = true;
 7         for (int i = 1; i <= n; i++) {
 8             dp[0][i] = dp[0][i - 1] && p.charAt(i - 1) == '*';
 9         }
10         for (int i = 1; i <= m; i++) {
11             for (int j = 1; j <= n; j++) {
12                 if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') {
13                     dp[i][j] = dp[i - 1][j - 1];
14                 } else if (p.charAt(j - 1) == '*') {
15                     dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
16                 }
17             }
18         }
19         return dp[m][n];
20     }
21 }

 

JavaScript实现

 1 /**
 2  * @param {string} s
 3  * @param {string} p
 4  * @return {boolean}
 5  */
 6 var isMatch = function (s, p) {
 7     let m = s.length;
 8     let n = p.length;
 9     let dp = [...Array(m + 1)].map((item) => Array(n + 1).fill(0));
10     dp[0][0] = true;
11     for (let i = 1; i <= n; i++) {
12         dp[0][i] = dp[0][i - 1] && p.charAt(i - 1) == '*';
13     }
14     for (let i = 1; i <= m; i++) {
15         for (let j = 1; j <= n; j++) {
16             if (
17                 s.charAt(i - 1) === p.charAt(j - 1) ||
18                 p.charAt(j - 1) === '?'
19             ) {
20                 dp[i][j] = dp[i - 1][j - 1];
21             } else if (p.charAt(j - 1) === '*') {
22                 dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
23             }
24         }
25     }
26     return dp[m][n];
27 };

 

LeetCode 题目总结