# 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;
    }
};