Question
Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
scould be empty and contains only lowercase lettersa-z.pcould be empty and contains only lowercase lettersa-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 = "a*"
Output: true
Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Example 3:
Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Example 4:
Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Example 5:
Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
Solution
As the problem has an optimal substructure, it is natural to cache intermediate results. We ask the question dp(i, j): does s[i:] and p[j:] match?
Without Kleene stars (the * wildcard character for regular expressions), the algorithm is simple. It answers whether s[i] must match p[j] and s[i+1:] matches p[j+1:]. When encountering *, there are two options:
- Ignore it. Match
s[i:]withp[j+2:]. - Use it.
s[i]must matchp[j]and the patternp[j:]matchess[i+1:].
In terms of time complexity, dp(i, j) can be called once for any i, j, and each call is \(O(1)\). Thus the time complexity is \(O(SP)\). The space complexity is \(O(SP)\) as well because the result for every i, j can be cached.
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
memo = dict()
def dp(i, j):
if (i, j) not in memo:
if j == len(p):
res = i == len(s)
else:
match = i < len(s) and p[j] in {s[i], '.'}
if j + 1 < len(p) and p[j + 1] == '*':
res = dp(i, j + 2) or (match and dp(i + 1, j))
else:
res = match and dp(i + 1, j + 1)
memo[i, j] = res
return memo[i, j]
return dp(0, 0)