Problem Statement: Wildcard Matching
Given two strings s
and p
, return true
if s
matches p
(with wildcard characters), and false
otherwise.
The string p
can contain the following wildcard characters:
?
: Matches exactly one character.*
: Matches any sequence of characters (including the empty sequence).
Example:
Example 1:
Input: s = "aa", p = "a*"
Output: true
Explanation: "a*" matches "aa" because '*' can match the second 'a'.
Example 2:
Input: s = "mississippi", p = "mis*is*p*."
Output: false
Example 3:
Input: s = "adceb", p = "*a*b"
Output: true
Explanation: The pattern "*a*b" matches the string "adceb".
Approach:
The problem can be solved using Dynamic Programming (DP). The idea is to use a 2D DP table where dp[i][j]
represents whether the substring s[0..i-1]
matches the pattern p[0..j-1]
.
Steps:
- Base Case:
dp[0][0] = true
: An empty string matches an empty pattern.dp[i][0] = false
fori > 0
: A non-empty string cannot match an empty pattern.dp[0][j] = true
for allj
where the pattern consists only of*
. This is because*
can match any sequence of characters, including the empty string.
- Filling the DP Table:
- For each character in the string
s
and the patternp
:- If
p[j-1] == s[i-1]
orp[j-1] == '?'
, thendp[i][j] = dp[i-1][j-1]
, meaning the current character ins
matches the current character inp
. - If
p[j-1] == '*'
, then we have two possibilities:dp[i][j] = dp[i-1][j]
: The*
matches at least one character ins
.dp[i][j] = dp[i][j-1]
: The*
matches zero characters ins
.
- If
- For each character in the string
- Final Result:
- The value of
dp[len(s)][len(p)]
will give the result of whether the entire strings
matches the patternp
.
- The value of
Dynamic Programming Solution:
Python Code:
def isMatch(s: str, p: str) -> bool:
# dp[i][j] will be True if s[0...i-1] matches p[0...j-1]
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
# Initial condition: empty string matches empty pattern
dp[0][0] = True
# If the pattern starts with '*' it can match the empty string
for j in range(1, len(p) + 1):
if p[j - 1] == '*':
dp[0][j] = dp[0][j - 1]
# Fill the dp table
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if p[j - 1] == s[i - 1] or p[j - 1] == '?':
dp[i][j] = dp[i - 1][j - 1]
elif p[j - 1] == '*':
dp[i][j] = dp[i - 1][j] or dp[i][j - 1]
# The bottom-right corner will contain the answer
return dp[len(s)][len(p)]
Explanation of the Code:
- Initialization:
- We initialize a 2D DP table
dp
of size(len(s) + 1) x (len(p) + 1)
, where each celldp[i][j]
will store whether the substrings[0..i-1]
matches the patternp[0..j-1]
. dp[0][0] = True
because an empty string matches an empty pattern.- For the first row (
dp[0][j]
), if the pattern starts with*
, it can match the empty string, so we setdp[0][j]
toTrue
for any*
characters in the pattern.
- We initialize a 2D DP table
- Filling the DP Table:
- We iterate through each character in
s
andp
and apply the rules:- If the current character in the pattern is
?
, it matches any single character ins
. - If the current character in the pattern is
*
, it can either match zero or more characters ins
. Thus, we check:- If
*
matches zero characters, check the cell to the left (dp[i][j-1]
). - If
*
matches at least one character, check the cell above (dp[i-1][j]
).
- If
- If the current character in the pattern is
- We iterate through each character in
- Final Answer:
- After filling the DP table,
dp[len(s)][len(p)]
will contain the final answer: whether the entire strings
matches the entire patternp
.
- After filling the DP table,
Time and Space Complexity:
- Time Complexity: O(m * n), where
m
is the length ofs
andn
is the length ofp
. We need to fill anm x n
DP table. - Space Complexity: O(m * n), as we are storing the DP table of size
m x n
.
Example Walkthrough:
Example 1:
Input: s = "aa", p = "a*"
- Initialize
dp
table. - First Row (
dp[0][j]
): Forp = "a*"
,dp[0][2] = True
, as*
can match the empty string. - Second Row (
dp[1][j]
): Fors = "a"
, the patterna*
matches:dp[1][1] = True
becausep[0] == s[0]
.dp[1][2] = True
because*
can match the seconda
.
- Third Row (
dp[2][j]
): Fors = "aa"
, the patterna*
matches:dp[2][1] = False
(no match).dp[2][2] = True
because*
matches the seconda
.
The final result is True
, as dp[2][2] = True
.
Example 2:
Input: s = "mississippi", p = "mis*is*p*."
- After filling the DP table, the value
dp[len(s)][len(p)]
will beFalse
, because the patternmis*is*p*.
does not match the string"mississippi"
.
Conclusion:
The Wildcard Matching problem is efficiently solved using Dynamic Programming. By filling a DP table and considering all possible ways a wildcard can match a sequence of characters, we can determine if the string matches the pattern with wildcards *
and ?
. The time complexity of O(m * n) is suitable for handling reasonably large inputs, where m
and n
are the lengths of the string and the pattern, respectively.