Is Match
LeetCode Problem
# https://leetcode.com/problems/regular-expression-matching/
# https://www.youtube.com/watch?v=HAA8mgxlov8
"""
If 2 special characters not present : regular string match
if "a." compare it to "aa" since "." can be any character.
"a." and "ab" also matches. but "a.." and "aa" = False
"a*" means character present before it can be repeated 0 -> infinite times
= [" ", "a", "aa", "aaa" ....]
"ab" = ".*" = ["", ., .. and so on] {one of the dots can be a and b}
Start from empty string, two choices : * or . [decision tree]
2 decisions, repeating n times (input string) = 2^n
With cache : O(n * m) or n^2
Top-Down
aab and c*a*b
i j
Decision Tree
.
/ \
c " "
2nd choice better, i is unchanged, j += 2 (no need for * because we will never repeat c as it doesn't match first string)
(i, j + 2)
aab and c*a*b [right after j there is a star that means "a" can be repeated 0 / more times]
i j
.
/ \
c " "
/ \
* " "
a
now a matches (j matches i), i += 1 and j remains same (as it can be repeated since * is the next char)
(i + 1, j)
in the end
aab and c*a*b
i j
s[i] == p[j] = (i + 1, j + 1)
aab and c*a*b
i j
if i out of bounds but j in bounds
a and a*b* :: Technically it does match
but if j out of bounds but i in bounds : doesn't work : must return false
Both out of bounds : Pattern has matched : return True
"""
from functools import cache
class Solution:
def isMatch(self, s: str, p: str) -> bool:
# top down memoization
dp = {}
@cache
def backtrack(i, j):
if (i, j) in dp:
return dp[(i, j)]
if i >= len(s) and j >= len(p):
return True
if j >= len(p):
return False
# i can be out of bounds still
# match between first character
match = i < len(s) and (
s[i] == p[j] or p[j] == "."
) # . matches to any character
# * has the highest precedence and first char in j can never be star
# can only use * if there is a match
if (j + 1) < len(p) and p[j + 1] == "*":
dp[(i, j)] = (
backtrack(i, j + 2) # don't use the *
or (match and backtrack(i + 1, j))
) # use the *
return dp[(i, j)]
if match:
dp[(i, j)] = backtrack(i + 1, j + 1)
return dp[(i, j)]
dp[(i, j)] = False
return False # otherwise
return backtrack(0, 0)