Welcome to Subscribe On Youtube
44. Wildcard Matching
Description
Given an input string (s
) and a pattern (p
), implement wildcard pattern matching with support for '?'
and '*'
where:
'?'
Matches any single character.'*'
Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
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'.
Constraints:
0 <= s.length, p.length <= 2000
s
contains only lowercase English letters.p
contains only lowercase English letters,'?'
or'*'
.
Solutions
Solution 1: Dynamic Programming
We define the state $dp[i][j]$ to represent whether the first $i$ characters of $s$ match the first $j$ characters of $p$.
The state transition equation is as follows:
\[dp[i][j]= \begin{cases} dp[i-1][j-1] & \text{if } s[i-1]=p[j-1] \text{ or } p[j-1]=\text{?} \\ dp[i-1][j-1] \lor dp[i-1][j] \lor dp[i][j-1] & \text{if } p[j-1]=\text{*} \\ \text{false} & \text{otherwise} \end{cases}\]The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the lengths of $s$ and $p$ respectively.
-
class Solution { public boolean isMatch(String s, String p) { int m = s.length(), n = p.length(); boolean[][] dp = new boolean[m + 1][n + 1]; dp[0][0] = true; for (int j = 1; j <= n; ++j) { if (p.charAt(j - 1) == '*') { dp[0][j] = dp[0][j - 1]; } } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') { dp[i][j] = dp[i - 1][j - 1]; } else if (p.charAt(j - 1) == '*') { dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; } } } return dp[m][n]; } }
-
class Solution { public: bool isMatch(string s, string p) { int m = s.size(), n = p.size(); vector<vector<bool>> dp(m + 1, vector<bool>(n + 1)); dp[0][0] = true; for (int j = 1; j <= n; ++j) { if (p[j - 1] == '*') { dp[0][j] = dp[0][j - 1]; } } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (s[i - 1] == p[j - 1] || p[j - 1] == '?') { dp[i][j] = dp[i - 1][j - 1]; } else if (p[j - 1] == '*') { dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; } } } return dp[m][n]; } };
-
class Solution: def isMatch(self, s: str, p: str) -> bool: m, n = len(s), len(p) dp = [[False] * (n + 1) for _ in range(m + 1)] dp[0][0] = True # if p starting with "*", then all true for dp[0][i] # or else, all false for dp[0][i] for j in range(1, n + 1): if p[j - 1] == '*': dp[0][j] = dp[0][j - 1] for i in range(1, m + 1): for j in range(1, n + 1): if s[i - 1] == p[j - 1] or p[j - 1] == '?': dp[i][j] = dp[i - 1][j - 1] # dp[i - 1][j], where j is always '*', all the way back to i-1==0 elif p[j - 1] == '*': dp[i][j] = dp[i - 1][j] or dp[i][j - 1] return dp[m][n]
-
func isMatch(s string, p string) bool { m, n := len(s), len(p) dp := make([][]bool, m+1) for i := range dp { dp[i] = make([]bool, n+1) } dp[0][0] = true for j := 1; j <= n; j++ { if p[j-1] == '*' { dp[0][j] = dp[0][j-1] } } for i := 1; i <= m; i++ { for j := 1; j <= n; j++ { if s[i-1] == p[j-1] || p[j-1] == '?' { dp[i][j] = dp[i-1][j-1] } else if p[j-1] == '*' { dp[i][j] = dp[i-1][j] || dp[i][j-1] } } } return dp[m][n] }
-
using System.Linq; public class Solution { public bool IsMatch(string s, string p) { if (p.Count(ch => ch != '*') > s.Length) { return false; } bool[,] f = new bool[s.Length + 1, p.Length + 1]; bool[] d = new bool[s.Length + 1]; // d[i] means f[0, j] || f[1, j] || ... || f[i, j] for (var j = 0; j <= p.Length; ++j) { d[0] = j == 0 ? true : d[0] && p[j - 1] == '*'; for (var i = 0; i <= s.Length; ++i) { if (j == 0) { f[i, j] = i == 0; continue; } if (p[j - 1] == '*') { if (i > 0) { d[i] = f[i, j - 1] || d[i - 1]; } f[i, j] = d[i]; } else if (p[j - 1] == '?') { f[i, j] = i > 0 && f[i - 1, j - 1]; } else { f[i, j] = i > 0 && f[i - 1, j - 1] && s[i - 1] == p[j - 1]; } } } return f[s.Length, p.Length]; } }
-
function isMatch(s: string, p: string): boolean { const m = s.length; const n = p.length; const f: number[][] = Array.from({ length: m + 1 }, () => Array.from({ length: n + 1 }, () => -1), ); const dfs = (i: number, j: number): boolean => { if (i >= m) { return j >= n || (p[j] === '*' && dfs(i, j + 1)); } if (j >= n) { return false; } if (f[i][j] !== -1) { return f[i][j] === 1; } if (p[j] === '*') { f[i][j] = dfs(i + 1, j) || dfs(i, j + 1) ? 1 : 0; } else { f[i][j] = (p[j] === '?' || s[i] === p[j]) && dfs(i + 1, j + 1) ? 1 : 0; } return f[i][j] === 1; }; return dfs(0, 0); }
-
class Solution { /** * @param string $s * @param string $p * @return boolean */ function isMatch($s, $p) { $lengthS = strlen($s); $lengthP = strlen($p); $dp = array(); for ($i = 0; $i <= $lengthS; $i++) { $dp[$i] = array_fill(0, $lengthP + 1, false); } $dp[0][0] = true; for ($i = 1; $i <= $lengthP; $i++) { if ($p[$i - 1] == '*') { $dp[0][$i] = $dp[0][$i - 1]; } } for ($i = 1; $i <= $lengthS; $i++) { for ($j = 1; $j <= $lengthP; $j++) { if ($p[$j - 1] == '?' || $s[$i - 1] == $p[$j - 1]) { $dp[$i][$j] = $dp[$i - 1][$j - 1]; } else if ($p[$j - 1] == '*') { $dp[$i][$j] = $dp[$i][$j - 1] || $dp[$i - 1][$j]; } } } return $dp[$lengthS][$lengthP]; } }