Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*' where:
- '.' Matches any single character.
- '*' Matches zero or more of the preceding element. The matching should cover the entire input string (not partial).
Input: s = "aa", p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
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".
Input: s = "ab", p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
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".
Input: s = "mississippi", p = "mis*is*p*."
Output: false
0 <= s.length <= 20
0 <= p.length <= 30
s contains only lowercase English letters.
p contains only lowercase English letters, '.', and '*'.
It is guaranteed for each appearance of the character '*', there will be a previous valid character to match.
Solutions (Click to expand)
If we were to exclude *
from our pattern then matching would be as simple that every ith character of string and pattern match or the ith character in the pattern is .
. Here are the conditions for matching a pattern of characters and .
with a string
- if
s[i]
andp[i]
are the same, the pattern matches if the preceding prefix matchess.substring(0, i) == p.substring(0, i)
- if
p[i] == "."
, the pattern match is the preceding prefix matchess.substring(0, i) == p.substring(0, i)
Once we introduce the *
, we can match a pattern to a string in a multitude of ways
- if
p[i] == "*"
, compare the operand of"*"
(character to the left of"*"
) and the current character ofs
,p[i - 1] == s[i]
: - if the operand of
"*"
does not match with the current character ofs
,p[i - 1] != s[i]
, we can considerx*
as empty. check if the preceding prefix matchesp.substring(0, i - 1) == s.substring(0, i)
- if the operand of
"*"
matches with the current character ofs
or is"."
we can:- count
x*
as a multiplex
check if thes.substring(0, i) == p
- count
x*
as a singlex
, in other words disregard"*"
, check ifs == p.substring(0, i)
- count
x*
as empty, in other words disregard"x*"
, check ifs == p.substring(0, i - 1)
- count
- if the operand of
If checking matches involves checking if prefixes match, we can most efficiently do that with memoization
We can have a grid of s.length + 1 * p.length + 1
the represents every possible substring of string and pattern can be
Here we can store the result of matching prefixes. The bottom right cell will store the result of matching the entire string with the entire pattern
Time: O(S*P)
where S is all possible substrings of s and P is all possible substrings of P
Space: O(S*P)