描述:一般字符串s 和 “模式串p” 是否 能够匹配的问题
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
解:
1.关键:
(1)好吧,我承认, 思路是借鉴评论区 的
(2)转移 状态 就是 前 s的前i个字符串 和 p的前j个字符串是否匹配
(3)设置一个 dp 矩阵 dp[s.size+1][p.size+1] //这么干 是为了 多出一种 “空 字符串的 情况
(4)分2中情况考虑 递推关系:
case1: 如果p[j-1]==‘*’(备注:从下标0开始用):
<1>可以 利用dp[i][j-2] 并且 让* 和它前面的那个字符 ”消失“
<2>可以利用dp[i-1][j] 并且 p[j-1]=='.' 万能的. , 不过这里 最难理解: 就是说 ,算了,这里有点不理解
Why?? 为什么 是dp[i-1][j] == true的时候呢???
答:可以 参见 题解中大佬题解的 评论区 "哦妈呀"的那位的 评论 解释, 很不错
解释一下当
p[j - 1] == *时,可以看到2、3这两种情况中,模式串下标索引为j,而不是j-1因为根据定义,
*前一字符可以出现任意次。重点注意任意次(情况2、3其实是,前一次字符出现次数为1次及以上)。以
"aaa"和"a*"这个例子为例,根据递推公式,当p[j - 1] == *,dp[i][j]状态值取决于dp[i-1][j] == true&&s[i - 1] == p[j - 2]。 我们思考的过程如下:
"a*"是否能和"aaa"匹配 这取决于:
"a*"能否和"aa"匹配,而这种情况又取决于:
"a*"能否和"a"匹配,毫不例外的,这种情况又依赖于于:
"a*"能否和""(空串) 匹配,这时满足情况1,即p[j-2]*的组合将前一字符出现次数看作0。"a*"和""(空串) 匹配嘛。 答案当然是匹配的!!!反过来想,如果下标我就是要写成
j - 1呢???
这就意味着状态转移变为:dp[i][j]状态值取决于dp[i-1][j-1] == true&&s[i - 1] == p[j - 2],这其实变相就是默认*只能让前一字符p[j - 2]出现一次,仅仅是一次!。仔细观察 ’.‘ 通配符,它能让当前字符变为任意1个(划重点,也是1)字符,关于它的递推公式中,模式串下标好巧不巧,也是j-1。这样一对比就很明显了。回到刚才的例子 所以
"a*"是否能和"aaa"匹配 ,这取决于"a"能否和"aa"匹配嘛? 这当然不取决于"a"能否和"aa"匹配,因为这种递推关系本质上就错了,结果也一定是错的。
<3>可以
case2:如果 p[j-1]!=*
<1>可以利用 dp[i-1][j-1] 并且 s[i-1] == p[j-1] 这个容易理解, 就是 最新加入的 两个字符 相等
<2>可以利用 dp[i-1][j-1] 并且 p[j-1] == '.' 只要 这个 位置 p模式串的字符 是万能字符 即可
2.代码:
class Solution {
public:bool isMatch(string s, string p) {//关于 字符串的 模式匹配的 问题 考虑借鉴 讨论区的 想法//利用 dp 动态规划 矩阵 进行 求解// size1+1 = m , size2+ 1 =nint m=s.size()+1;int n = p.size() + 1;vector> dp(m,vector(n,false)); // 初始化一个矩阵//如果 s是一个空的 字符串 , 需要 让字符串p进行 匹配 , 只有* //这个道具 让字符串p 变成一个空的字符串 ,//然后 将 p 和 一个空字符串 进行 匹配的 结果 作为 递推 关系的 初始条件dp[0][0]=true; // 2个空的 字符串 一定是匹配的 //如果 字符串p有 奇数个 字符 一定不可能匹配for(int j=2; j