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 '*'
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to wildcard matching is like trying to fit two jigsaw puzzles together by testing every possible way they might align. We check if the pattern can match the text by exploring all potential matches. If at any point a mismatch is found, we backtrack and try a different alignment.
Here's how the algorithm would work step-by-step:
def is_wildcard_matching(text, pattern):
text_index = 0
pattern_index = 0
star_index = -1
match_index = 0
while text_index < len(text):
if pattern_index < len(pattern) and \
(pattern[pattern_index] == text[text_index] or \
pattern[pattern_index] == '?'):
text_index += 1
pattern_index += 1
elif pattern_index < len(pattern) and pattern[pattern_index] == '*':
# Store the index of the '*' and current text index
star_index = pattern_index
match_index = text_index
pattern_index += 1
elif star_index != -1:
# Backtrack: match current text char with '*'
pattern_index = star_index + 1
match_index += 1
text_index = match_index
else:
return False
# Check for remaining characters in pattern
while pattern_index < len(pattern) and pattern[pattern_index] == '*':
pattern_index += 1
# If all characters in pattern are processed, it's a match
return pattern_index == len(pattern)
The best way to solve this is by using a strategy that remembers whether we've seen a particular combination of the main text and wildcard pattern before. This helps us avoid repeating work and makes the matching process much faster.
Here's how the algorithm would work step-by-step:
def is_wildcard_matching(text, pattern):
text_length = len(text)
pattern_length = len(pattern)
# Create a table to store matching results
dp_table = [[False] * (pattern_length + 1) for _ in range(text_length + 1)]
dp_table[0][0] = True
# Handles the case where the text is empty.
for pattern_index in range(1, pattern_length + 1):
if pattern[pattern_index - 1] == '*':
dp_table[0][pattern_index] = dp_table[0][pattern_index - 1]
for text_index in range(1, text_length + 1):
for pattern_index in range(1, pattern_length + 1):
if pattern[pattern_index - 1] == '?' or text[text_index - 1] == pattern[pattern_index - 1]:
dp_table[text_index][pattern_index] = dp_table[text_index - 1][pattern_index - 1]
elif pattern[pattern_index - 1] == '*':
# The '*' can represent 0 or more characters
dp_table[text_index][pattern_index] = dp_table[text_index][pattern_index - 1] or dp_table[text_index - 1][pattern_index]
else:
dp_table[text_index][pattern_index] = False
# Returns True if the whole text matches the whole pattern
return dp_table[text_length][pattern_length]
Case | How to Handle |
---|---|
Empty string s and empty pattern p | Should return true because an empty pattern matches an empty string. |
Empty string s and pattern p is only '*' | Should return true because '*' matches an empty string. |
String s is empty and pattern p is not empty (and not just '*') | Should return false unless the entire pattern consists of '*' characters. |
Pattern p is empty and string s is not empty | Should return false as there is no pattern to match the string. |
String s contains a long sequence of identical characters and pattern p contains a single '*' | The '*' should match the entire sequence, so algorithm must handle correctly. |
Pattern p contains multiple consecutive '*' characters | Multiple consecutive '*' should be treated as a single '*'. |
Pattern p ends with '*' and string s is non-empty | Should return true if the initial part of the pattern matches the start of the string. |
Long string s and long pattern p with many '*' and '?' characters, potentially causing stack overflow in a recursive solution | Dynammic programming approach can be used to avoid deep recursion and stack overflow. |