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
# Only '*' can match with empty string
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 p[j-1] == '*':
# '*' matches zero (dp[i][j-1]) or one/more (dp[i-1][j])
dp[i][j] = dp[i][j-1] or dp[i-1][j]
elif p[j-1] == '?' or s[i-1] == p[j-1]:
dp[i][j] = dp[i-1][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, false));
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 (p[j-1] == '*')
dp[i][j] = dp[i][j-1] || dp[i-1][j];
else if (p[j-1] == '?' || s[i-1] == p[j-1])
dp[i][j] = dp[i-1][j-1];
}
}
return dp[m][n];
}
};
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 (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];
}
}
var isMatch = function(s, p) {
const m = s.length, n = p.length;
const dp = Array.from({length: m+1}, () => Array(n+1).fill(false));
dp[0][0] = true;
for (let j = 1; j <= n; ++j)
if (p[j-1] === '*')
dp[0][j] = dp[0][j-1];
for (let i = 1; i <= m; ++i) {
for (let j = 1; j <= n; ++j) {
if (p[j-1] === '*')
dp[i][j] = dp[i][j-1] || dp[i-1][j];
else if (p[j-1] === '?' || s[i-1] === p[j-1])
dp[i][j] = dp[i-1][j-1];
}
}
return dp[m][n];
};
Given two strings, s (the input string) and p (the pattern), determine if s matches the pattern p. The pattern may include the wildcard characters:
'?' – matches any single character.'*' – matches any sequence of characters (including the empty sequence).true if the entire string s matches the pattern p, and false otherwise. Each character in s can only be matched once, and the match must cover the entire string.
At first glance, the problem seems similar to regular expression matching, but with only '?' and '*' as special characters. A brute-force approach would try all possible ways to match '*' to zero or more characters, which quickly becomes infeasible for long strings due to exponential possibilities.
To optimize, we notice that for each position in s and p, the result depends only on the decisions made previously. This property is ideal for dynamic programming (DP), where we can store and reuse results of subproblems. By using a DP table to keep track of matches between all prefixes of s and p, we can avoid redundant computations and efficiently solve the problem.
We'll use a two-dimensional dynamic programming (DP) table where dp[i][j] is true if the first i characters of s match the first j characters of p.
dp[0][0] is true since an empty pattern matches an empty string.dp[0][j] (empty string vs pattern), only possible if all previous pattern characters are '*' (since '*' can represent empty).p[j-1] is '*': We have two choices:
'*' as matching zero characters: dp[i][j-1]'*' as matching one or more characters: dp[i-1][j]dp[i][j] = dp[i][j-1] || dp[i-1][j].
p[j-1] is '?' or matches s[i-1]: dp[i][j] = dp[i-1][j-1]dp[i][j] = false.dp[m][n], where m and n are the lengths of s and p, respectively.This approach ensures that we only process each subproblem once, leading to efficient performance.
Let's consider s = "adceb" and p = "*a*b".
dp[0][0] = truep[0] is '*', dp[0][1] = truedp[0][j] are falsei and j, fill according to rules above.p[0] ('*'), dp[1][1] = dp[1][0] || dp[0][1], and so on.p[1] is 'a', dp[1][2] checks if s[0] is 'a' (it is), so dp[1][2] = dp[0][1].dp[5][4] = true, so the function returns true.This step-by-step filling ensures we consider all possible ways '*' can match sequences, and '?' matches single characters.
O(2^{m+n}) due to trying all ways '*' can expand.
O(mn) where m and n are the lengths of s and p, since we fill each cell of the DP table once.
O(mn) for the DP table. (Can be optimized to O(n) with rolling arrays.)
Wildcard Matching is a classic dynamic programming problem. By recognizing overlapping subproblems and using a DP table to store intermediate results, we efficiently handle the complexity introduced by the '*' wildcard. The approach is systematic and avoids redundant computation, making it both elegant and practical for large inputs.