**
力扣10:正则表达式的匹配——动态规划
**
题目:给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 . 和 * 的正则表达式匹配。
" . " 匹配任意单个字符
" * " 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
示例 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 = “cab”
输出:true
解释:因为 '’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:s = “mississippi” p = "misisp."
输出:false
提示:
0 <= s.length <= 20
0 <= p.length <= 30
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符
解题思路:一开始的思路是想从左往右匹配,但因为不知道重复的字母会有几个并且字符后面是否会有*也会影响结果,所以分析起来过于复杂。于是采用从右往左的解决思路。
而s的第i个与p的第j个是否匹配取决于两点
1.第i个和第j个是否匹配
2.s的前i-1个和p的前j-1个子串是否匹配
于是可以采用动态规划的思想。将一个问题划分为若干个子问题。
用bool型二维数组dp[n][m]来储存结果。(dp[i][j]==true表示s[0,i-1]和p[0,j-]的字符串匹配)
然后开始分情况讨论:
1.当p[j-1] == s[i-1]时,这时dp[i][j]取决于前一个字符串是否匹配上,所以dp[i][j] = dp[i-1][j-1].(p[j-1],s[i-1]储存的是p的第j个字符和s的第i个字符)
2.当p[j-1] == '.'时,p[j-1]与s的任意字符都匹配,所以dp[i][j] = dp[i-1][j-1].
3.当p[j-1] == ’ * '时,又要分两种情况讨论:
(1)p[j-2]与s[i-1]不匹配,这时要将p[j-2]消掉,所以dp[i][j]=d[i][j-2];
(2)p[j-2]与s[i-1]匹配,这时可能是单个字符匹配,多个字符匹配,或者没有匹配的情况。所以dp[i][j]分别等于dp[i][j-1],dp[i-1][j],dp[i][j-2].
另外需要考虑边界条件:
1.s,p都是空串的时候,这时s,p是匹配的,所以dp[0][0]=true.
2.s是空串而p不是空串时,这时p要想匹配只能是p的右端是 * 然后干掉一个字符,如此往复直到p为空串。
3.s不是空串而p是空串时,一定不匹配。
代码C++:
bool isMatch(string s, string p)//动态规划,dp[i][j]表示s[0,i-1]的字符与p[0][j-1]的字符匹配
{
int n1 = s.size();
int n2 = p.size();
bool dp[n1 + 1][n2 + 1];
memset(dp, false, (n1 + 1) * (n2 + 1));//初始化都为false
dp[0][0] = true;//都是空串时匹配
if (!s.empty() && p.empty())//s不是空串而p是空串时,一定不匹配
return false;
for (int i = 1; i <= n2; i++)//s是空串时,p的第i个字符是 *,则它的状态取决于第i-2个字符的状态,也就是说第i个字符是 * 号则干掉它前一个字符和它自己。
{
if (p[i - 1] == '*')
dp[0][i] = dp[0][i - 2];
}
for (int i = 1; i <= n1; i++)
for (int j = 1; j <= n2; j++)
{
if (s[i - 1] == p[j - 1])
{
dp[i][j] = dp[i - 1][j - 1];
}
else if (p[j - 1] == '.')
{
dp[i][j] = dp[i - 1][j - 1];
}
else if (p[j - 1] == '*')
{
if (p[j - 2] == s[i - 1] || (p[j - 2] == '.'))
{
dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];
}
else
{
dp[i][j] = dp[i][j - 2];
}
}
}
return dp[n1][n2];
}
因为笔者水平有限,所以文章中难免会出现错误或者不足的地方,望大家斧正。