10. Regular Expression Matching
题目要求
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).
The function prototype should be:
bool isMatch(const char *s, const char *p)
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
题目分析
1. 使用递归
对于串s
和模式p
,有:
1. 如果p[1]
是常规字符,那么在p[0]
等于s[0]
或者 p[0]
是通配符.
的时候,问题等价与子串s[1: ]
和子模式p[1: ]
匹配。
2. 如果p[1]
是字符*
,问题分为两类,一是s[0]
继续匹配到p[0]
,那么问题等价于串s[1: ]
与模式p
匹配;二是s[0]
不匹配到p[0]
,那么问题等价于串s
匹配p[2: ]
。
写成代码有:
class Solution {
public:
bool isMatch(string s, string p) {
return isMatchImpl(s.c_str(), s.size(), p.c_str(), p.size());
}
bool isMatchImpl(const char* s, size_t s_len, const char* p, size_t p_len) {
if (p_len == 0) return s_len == 0;
bool head = s_len != 0 && (p[0] == s[0] || *p == '.');
if (p_len >= 2 && *(p + 1) == '*') {
return isMatchImpl(s, s_len, p + 2, p_len - 2) ||
(head && isMatchImpl(s + 1, s_len - 1, p, p_len));
} else {
return head && isMatchImpl(s + 1, s_len - 1, p + 1, p_len - 1);
}
}
};
2. 保存中间状态
在上述解法中,如果大量出现重复匹配模式*
,那么在递归的时候会重复计算部分子串与子模式的匹配问题。为了减少无效的重复计算,可以使用一个二维数组保存状态,提高性能。
class Solution {
char** store;
int slen, plen;
bool isMatch(string s, string p) {
slen = s.size(), plen = p.size();
store = new char*[slen + 1]();
for (int i = 0; i <= slen; ++i) {
store[i] = new char[plen + 1]();
}
bool result = isMatchImpl2(0, 0, s.c_str(), p.c_str());
for (int i = 0; i <= slen; ++i) {
delete[] store[i];
}
delete[] store;
return result;
}
bool isMatchImpl(int i, int j, const char* s, const char* p) {
if (store[i][j] != 0) {
return store[i][j] == 2;
}
bool result;
if (j == plen) {
result = i == slen;
} else {
bool head = i < slen && (p[j] == s[i] || p[j] == '.');
if (j + 1 < plen && p[j + 1] == '*') {
result = isMatchImpl(i, j + 2, s, p) ||
(head && isMatchImpl(i + 1, j, s, p));
} else {
result = head && isMatchImpl(i + 1, j + 1, s, p);
}
}
store[i][j] = result ? 2 : 1;
return result;
}
};