原本准备在暑假学习DP算法的,但最近感觉心里少了什么东西一样,原来是自己不了解DP 导致的空落感,所以把官方的答案 和 度娘的解释看了一遍,自己用 Debug 测试了一下,把自己的所想分享给大家 . . .
.
前文链接(递归解决正则表达式匹配):LeetCode算法 —— 正则表达式匹配(详解官方递归思想)
题目:
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例此处就不粘贴了
官方用DP思想写的代码中,重要的地方我已经用红色方框标明了起来,下来我们来讨论一下他们的作用 . . .
官方思想解析:
上面的解析中画红色框的部分与上面代码中画框的部分相对应 . . .
切记程序中对数组下标的处理( + 1 ?)
.
下面我来带大家走进 Debug的世界,看看这个 DP 是怎么工作的 . . .
我们使用下面的数据进行测试(大家也可以试试别的数据):1) 首先根据上面官方解析,我们准备一个容器,准备工作到位:
vector <vector<int> > vec(m + 1, vector<int>(n + 1));
vec[0][0] = true;
2) 遍历容器里的元素 vec[i][j]
(每个元素表示一个状态,官方解析思想上面有):
for (size_t i = 0; i <= m; ++i)
{
for (size_t j = 1; j <= n; ++j)
{
}
}
这里的 m是 s的大小,n是 p的大小 . . .
这里的 i 是从 0 开始的,上面的截图部分有误,还请谅解 ^ _ ^
.
3)准备一个判断对应字符是否相等的方法(这里很佩服官方的作法,用的是 Lambda表达式):
auto JudgeIsNoMatch = [&s, &p](int i, int j) {
if (i == 0) // 如果当前匹配s的长度为 0,则直接返回
return false;
if (p[j - 1] == '.') // . 可匹配万物
return true;
return s[i - 1] == p[j - 1]; // 判断是否相等
};
.
4)当前p中的判断字符是否为 * 处理的部分:
// 等于 * 时处理的步骤
if (p[j - 1] == '*') {
vec[i][j] |= vec[i][j - 2]; // 判断是否可以舍弃 *号
// j 与 i 前的所有字符匹配,保存记录判断到最后
// 可以这个判断有点萌币,不急,看我下面的Debug 测试就知道了 )``^ _ ^``
if (JudgeIsNoMatch(i, j - 1)) {
vec[i][j] |= vec[i - 1][j]; // a* 要和 s中的 i - 1 个字符要匹配
}
}
// 不等于 * 时处理的步骤
else {
// 直接判断是否相等
if (JudgeIsNoMatch(i, j)) {
// i - 1 个 s中的字符 要和 j - 1 个 p中的字符要相等
vec[i][j] |= vec[i - 1][j - 1];
}
}
.
5)开始我们 Debug测试,看看我们的最终图是如何求出解来的:
我们最终的结果就是判断
vec[m][n] 是否为 1
就行了,说明我们已经完美的匹配结束了 . . .
.
return vec[m][n];
.
.
.
.
.
执行的代码是:
vec[i][j] |= vec[i - 1][j];
因为 if中判断成功了,说明相应的字符是相同的,并且之间的字符也判断相同了(vec[i - 1][j])证明 . . .
.
.
.
浪子花梦
一个有趣的程序员 ~