Regular Expression Matching
LeetCode #10 · Hard · Dynamic Programming · C++ solution with worked-out approach and complexity analysis.
Approach
Dynamic Programming (Top-Down with Memoization)
Key insight
The problem has optimal substructure and overlapping subproblems. We can use recursion with memoization to solve it efficiently.
Strategy
- 1Base Case: If we reach the end of the pattern (j == pattern.size()),
- 2Check if the first character of the current substring matches (text[i]
- 3Handle the '*' wildcard (peek at p[j+1]):
- 4Handle standard matching when no '*' follows: Match the character and
Time
O(S * P)
S and P are lengths of string and pattern.
Space
O(S * P)
the memoization table.
Problem description(from LeetCode)
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).
Examples
Example 1
- Input:
- s = "aa", p = "a"
- Output:
- false
Constraints
- •1 <= s.length <= 20
- •1 <= p.length <= 20
- •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.
C++ Solution
solution.cpp
class Solution {
public:
vector<vector<int>> memo;
bool isMatch(string s, string p) {
memo.assign(s.size() + 1, vector<int>(p.size() + 1, -1));
if (p == "") return s == "";
return dp(0, 0, s, p);
}
bool dp(int i, int j, const string &text, const string &pattern) {
if (memo[i][j] != -1) return memo[i][j];
bool result;
if (j == pattern.size()) {
result = (i == text.length());
} else {
bool firstMatch =
(i < text.size() && (text[i] == pattern[j] || pattern[j] == '.'));
if (j + 1 < pattern.size() && pattern[j + 1] == '*') {
// Case 1: Match 0 of the preceding element (jump over pattern[j]*)
// Case 2: Match 1 or more (only if firstMatch is true, move string
// pointer)
result = (dp(i, j + 2, text, pattern) ||
(firstMatch && dp(i + 1, j, text, pattern)));
} else {
// Normal character match
result = (firstMatch && dp(i + 1, j + 1, text, pattern));
}
}
return memo[i][j] = result;
}
};