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 lettersa-z
.p
could be empty and contains only lowercase lettersa-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 };