# 44. Wildcard Matching
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 letters a-z.
p could be empty and contains only lowercase letters a-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
# Solution
Approach 1: DP.
Approach 2: greedy -- match greedily until we meet a star, then anchor that on both s and p to be able to get back to them. Running time O(MN)
.
Approach 3: (Memory Limit Exceeded) Recursion with hash table.
# Code (Python)
Approach 1:
def isMatch(self, s: str, p: str) -> bool:
# match[i][j] -- s[:i] matches p[:j]
# if p[j-1] is *, then match[i][j] = match[i][j-1] or match[i-1][j]
match = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
match[0][0] = True
for j in range(1, len(p) + 1):
if p[j-1] == '*' and match[0][j-1]:
match[0][j] = True
for i in range(1, len(s) + 1):
for j in range(1, len(p) + 1):
if p[j-1] == '?':
match[i][j] = True if match[i-1][j-1] else False
elif p[j-1] == '*':
match[i][j] = True if match[i][j-1] or match[i-1][j] else False
else:
match[i][j] = True if match[i-1][j-1] and p[j-1] == s[i-1] else False
return match[-1][-1]
Approach 2:
def isMatch(self, string: str, pattern: str) -> bool:
# http://chaoren.is-programmer.com/posts/42771.html
# idea: match greedily until we meet a star, then anchor that on both s and p to be able to get back to them
# running time O(MN), e.g. string = aaaaaaaa, pattern = *aaaab
# pointers at the string/pattern
s, p = 0, 0
# record the location that a star matches up to
matched_s, star_location = 0, -1
# exhaust the string
while s < len(string):
# p < len(pattern) is important in case we run out of the pattern
if p < len(pattern) and (string[s] == pattern[p] or pattern[p] == '?'):
s += 1
p += 1
# anchor down the matched parts when we first meet a start
elif p < len(pattern) and pattern[p] == '*':
matched_s = s
star_location = p
p += 1 # start with matching 0 chars of string
elif star_location == -1:
return False
else:
# drag points s and p back to match the start with 1 more char of string
matched_s += 1
s = matched_s
p = star_location + 1
# then exhaust the pattern
while p < len(pattern) and pattern[p] == '*':
p += 1
return p == len(pattern)
# Code (C++)
Approach 1:
// DP.
class Solution {
public:
bool isMatch(string s, string p) {
int sSize = s.size();
int pSize = p.size();
bool match[sSize+1][pSize+1];
match[sSize][pSize] = true;
for (int i = 0; i < sSize; ++i)
{
match[i][pSize] = false;
}
for (int i = pSize - 1; i >= 0; --i)
{
match[sSize][i] = (p[i] == '*') && match[sSize][i+1];
}
for (int i = sSize - 1; i >= 0; --i)
{
for (int j = pSize - 1; j >= 0; --j)
{
if (p[j] == '*')
match[i][j] = match[i][j+1] || match[i+1][j];
else
match[i][j] = (p[j] == '?' || p[j] == s[i]) &&
match[i+1][j+1];
}
}
return match[0][0];
}
};
Approach 2:
// Greedy.
class Solution {
public:
bool isMatch(string s, string p) {
int sSize = s.size();
int pSize = p.size();
int sHead = 0;
int pHead = 0;
int sAnchor = -1;
int pAnchor = -1;
while (sHead < sSize)
{
if (pHead < pSize && (p[pHead] == '?' || p[pHead] == s[sHead]))
{
sHead++;
pHead++;
}
else if (pHead < pSize && p[pHead] == '*')
{
sAnchor = sHead;
pAnchor = pHead;
pHead++;
}
else if (pAnchor < 0)
{
return false;
}
else
{
sHead = ++sAnchor;
pHead = pAnchor;
}
}
while (pHead < pSize)
{
if (p[pHead] != '*')
return false;
pHead++;
}
return true;
}
};
Approach 3:
// Memory Limit Exceeded.
class Solution {
private:
unordered_map<string,bool> umap;
public:
bool isMatch(string s, string p) {
string key = s + "," + p;
if (umap.find(key) != umap.end())
return umap[key];
bool match = false;
if (p.size() == 0)
{
match = s.size() == 0;
}
else if (p[0] == '*')
{
match = isMatch(s, p.substr(1)) ||
s.size() > 0 && isMatch(s.substr(1), p);
}
else
{
match = s.size() > 0 && (p[0] == '?' || p[0] == s[0]) &&
isMatch(s.substr(1), p.substr(1));
}
umap[key] = match;
return match;
}
};