LeetCode 44. Wildcard Matching

September 02, 2020

This problem can't be solved greedily due to examples like {s = 'ad', p = '*a*'}.

We can solve it with a dynamic programming solution.

import re
import unittest

class Test(unittest.TestCase):

    def setUp(self):
        self.s = Solution()

    def test_examples(self):
        self.assertFalse(self.s.isMatch("aa", "a"))
        self.assertTrue(self.s.isMatch("aa", "*"))
        self.assertFalse(self.s.isMatch("cb", "?a"))
        self.assertTrue(self.s.isMatch("adceb", "*a*b"))
        self.assertFalse(self.s.isMatch("acdcb", "a*c?b"))
        self.assertFalse(self.s.isMatch("leetcode", "*e*t?d*"))

    def test_asterisks(self):
        self.assertTrue(self.s.isMatch("eraueheejdieae", "*e"))

class Solution:

    def __init__(self):
        # cache
        self.c = {}
        self.asteriskre = re.compile("^\**$")

    def isMatch(self, s: str, p: str) -> bool:
        if not s or not p:
            # If we've exhausted either s or p,
            # we have a match iff s is empty and p contains only *"s.
            return not s and self.asteriskre.match(p)
        if (s,p) in self.c:
            return self.c[(s,p)]
        if p[0] == "?" or p[0] == s[0]:
            return self.isMatch(s[1:], p[1:])
        if p[0] != "*":
            return False
        m = self.isMatch(s[1:], p)
        if not m:
            m = self.isMatch(s, p[1:])
        self.c[(s,p)] = m
        return m

if __name__ == "__main__":
    unittest.main()