Leetcode经典题型:10 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false
思路 动态规划
- (一)状态 状态的选取最困难
f[i][j]表示s1的前i个字符,和s2的前j个字符,能否匹配 即s[0:i-1]和s2[0:j-1]能否匹配
- (二)转移方程
1 如果s1的第 i 个字符和s2的第 j 个字符相同,或者s2的第 j 个字符为 “.”
- f[i][j] = f[i - 1][j - 1]
2 如果s2的第 j 个字符为 *
- 若s2的第 j 个字符匹配 0 次第 j - 1 个字符
f[i][j] = f[i][j - 2] 比如(ab, abc*) - 若s2的第 j 个字符匹配至少 1 次第 j - 1 个字符,
f[i][j] = f[i - 1][j] and s1[i] == s2[j - 1] or s[j - 1] == ‘.’
这里注意不是 f[i - 1][j - 1], 举个例子就明白了 (abbb, ab*) f[4][3] = f[3][3]
- (三)初始化
f[0][i] = f[0][i - 2] && s2[i] == *
即s1的前0个字符和s2的前i个字符能否匹配
- (四)结果
f[m][n]
实现
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
class Solution {
public:
bool isMatch(string s, string p) {
int s_len = s.size();
int p_len = p.size();
vector<vector<int>> dp(s_len + 1, vector<int>(p_len + 1, 0));
dp[0][0] = 1;
for (int j = 2; j <= p_len; j++) {
dp[0][j] = (dp[0][j - 2] && (p[j - 1] == '*'));
}
for (int i = 1; i <= s_len; i++) {
for (int j = 1; j <= p_len; j++) {
if (s[i - 1] == p[j - 1] || p[j - 1] == '.') {
dp[i][j] = dp[i - 1][j - 1];
}
else if (p[j - 1] == '*') {
if (s[i - 1] == p[j - 2] || p[j - 2] == '.')
dp[i][j] = max(dp[i][j - 2], dp[i - 1][j]);
else
dp[i][j] = dp[i][j - 2];
}
}
}
for (int i = 0; i < s_len+1; i++) {
for (int j = 0; j < p_len+1; j++) {
cout << dp[i][j];
}
cout << endl;
}
return dp[s_len][p_len];
}
};
int main()
{
string a = "aaabc";
string b = "a*bc";
Solution s;
cout<<s.isMatch(a, b) <<endl;
system("pause");
return 0;
}
注释版
class Solution {
public:
bool isMatch(string s, string p) {
int s_len = s.size();
int p_len = p.size();
vector<vector<int>> dp(s_len + 1, vector<int>(p_len + 1, 0));
dp[0][0] = 1; //空串和空串总是相等的
if (p_len > 1) //p>0的情况下, dp[0][1]总是0 1处无论是什么字符都不相等
dp[0][1] = 0;
for (int j = 2; j <= p_len; j++) {
dp[0][j] = (dp[0][j - 2] && (p[j - 1] == '*'));
}
for (int i = 1; i <= s_len; i++) { //i和j都从1开始,因为表示s1的前i个字符
for (int j = 1; j <= p_len; j++) {
//一 如果s1的第 i 个字符和s2的第 j 个字符相同,那么是否相等要看dp[i - 1][j - 1]的状态;
if (s[i - 1] == p[j - 1] || p[j - 1] == '.') {
dp[i][j] = dp[i - 1][j - 1];
}
//二 如果字符不相等,还有一次挽回的机会 == '*'
else if (p[j - 1] == '*') {
//二者相等时*前字符出现情况 aa 0 ba 1 aaa n
//a*作为: 空字符, 单字符 a, 多字符 aaa... aaa* ba* a*
if (s[i - 1] == p[j - 2] || p[j - 2] == '.')
//0dp[i][j - 2] or 1dp[i][j - 1] or ndp[i - 1][j] 1次的情况可以和n合并
dp[i][j] = max(dp[i][j - 2], dp[i - 1][j]);
else
//根据匹配规则, 比较匹配串*的前一个字符与字符串中前一个字符 aa
//二者不相等时, a*只有作为空字符串时才可能匹配, aac*
//这就是说, 略过前一个字符, *字符对应的状态与字符串中前2个字符的状态一致
dp[i][j] = dp[i][j - 2];
}
//三 如果不相等也不等于'*',两个字符串必然不等,赋0(因为初始化就是0,所以一下语句可有可无)
else dp[i][j] = 0;
}
}
for (int i = 0; i < s_len+1; i++) {
for (int j = 0; j < p_len+1; j++) {
cout << dp[i][j];
}
cout << endl;
}
return dp[s_len][p_len];
}
};
1, If p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1];
2, If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1];
3, If p.charAt(j) == '*':
here are two sub conditions:
1 if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //in this case, a* only counts as empty
2 if p.charAt(i-1) == s.charAt(i) or p.charAt(i-1) == '.':
dp[i][j] = dp[i-1][j] //in this case, a* counts as multiple a
or dp[i][j] = dp[i][j-1] // in this case, a* counts as single a
or dp[i][j] = dp[i][j-2] // in this case, a* counts as empty
参考
Leetcode 思路
https://leetcode-cn.com/problems/regular-expression-matching/solution/dong-tai-gui-hua-ji-hui-su-by-song-19/
https://leetcode-cn.com/problems/regular-expression-matching/solution/qing-xi-yi-dong-e-by-_seekdream/
https://leetcode.com/problems/regular-expression-matching/discuss/5651/Easy-DP-Java-Solution-with-detailed-Explanation/?utm_source=LCUS&utm_medium=ip_redirect_q_uns&utm_campaign=transfer2china