LeetCode算法 —— 正则表达式匹配(详解官方动态规划思想)

原本准备在暑假学习DP算法的,但最近感觉心里少了什么东西一样,原来是自己不了解DP 导致的空落感,所以把官方的答案 和 度娘的解释看了一遍,自己用 Debug 测试了一下,把自己的所想分享给大家 . . .
.
前文链接(递归解决正则表达式匹配):

LeetCode算法 —— 正则表达式匹配(详解官方递归思想)


此文章主要讲解 DP的运行过程 !!!

在这里插入图片描述

题目:
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

示例此处就不粘贴了

官方代码如下:
在这里插入图片描述

官方用DP思想写的代码中,重要的地方我已经用红色方框标明了起来,下来我们来讨论一下他们的作用 . . .

官方思想解析:

在这里插入图片描述
在这里插入图片描述
.

上面的解析中画红色框的部分与上面代码中画框的部分相对应 . . .

切记程序中对数组下标的处理( + 1 ?)


.

下面我来带大家走进 Debug的世界,看看这个 DP 是怎么工作的 . . .

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];


.

Debug 测试结果

  1. 使用断点,调试程序:
    在这里插入图片描述

.

  1. 当 i = 1,j = 1 时,执行 else 语句:
    在这里插入图片描述

    因为 vec[0][0] = 1,所以 vec[1][1] |= vec[0][0] == 1;
    .
    此时,状态图如下:
    在这里插入图片描述

.

  1. 当 i = 2,j = 2 时,执行 else 语句:
    在这里插入图片描述

    原理与上面相同
    在这里插入图片描述

.

  1. 当 i = 2,j = 4 时,执行 if 中的语句:
    在这里插入图片描述

    此时,这句代码将起到作用:
    vec[i][j] |= vec[i][j - 2];
    此处的 a* 将舍弃,这样才能满足题目的意思(所做的一切都是为下面做服务) . . .
    在这里插入图片描述

  2. 当 i = 3,j = 3 时,与 2、3 是相同的:
    在这里插入图片描述

.

  1. 当 i = 3,j = 4时,执行下面的语句:
    在这里插入图片描述

    执行的代码是:

    vec[i][j] |= vec[i - 1][j];

    因为 if中判断成功了,说明相应的字符是相同的,并且之间的字符也判断相同了(vec[i - 1][j])证明 . . .在这里插入图片描述

.

  1. 当 i = 4, j = 4时,同 6 相同:
    在这里插入图片描述
    在这里插入图片描述

.

文章可能有许多写的不好的地方,还请大家谅解,因为我太困了 (>_<)

.

祝大家端午节安康←_←


浪子花梦

一个有趣的程序员 ~

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
正则表达式匹配是一个经典的算法问题,主要是判断一个字符串是否能够完全匹配给定的正则表式。 在LeetCode上,也有一道关于正则表达式匹配的题目,题目编号是10。这道题目要求实现一个支持 '.' 和 '*' 的正则表达式匹配,其中 '.' 可以匹配任意单个字符,'*' 可以匹配零个或多个前面的元素。 解决这道题可以使用动态规划思想,具体的思路如下: 1. 创建一个二维数组dpdp[i][j]表示s的前i个字符与p的前j个字符是否匹配。 2. 初始化dp为true,表示空字符串与空正则表达式是匹配的。 3. 初始化dp[i]为false,表示非空字符串与空正则表达式是不匹配的。 4. 初始化dp[j],如果p[j-1]是"*",则dp[j]的值取决于dp[j-2]的值,表示将p[j-2]与p[j-1]去掉后的正则表达式是否匹配空字符串。 5. 对于其它的dp[i][j],分成两种情况: - 如果p[j-1]是"."或者与s[i-1]相等,则dp[i][j]的值取决于dp[i-1][j-1]的值,表示将s[i-1]和p[j-1]去掉后的字符串是否匹配。 - 如果p[j-1]是"*",则dp[i][j]的值取决于以下两种情况: - dp[i][j-2]的值,表示将p[j-2]和p[j-1]去掉后的正则表达式是否匹配s的前i个字符。 - dp[i-1][j]的值,表示将s[i-1]与p[j-2]匹配后的字符串是否匹配p的前j个字符。 6. 最后返回dp[s.length()][p.length()]的值,表示整个字符串s与正则表达式p是否完全匹配。 以上是一种使用动态规划解决正则表达式匹配问题的思路,具体的实现可以参考LeetCode官方提供的递归思路的解法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [LeetCode算法 —— 正则表达式匹配详解官方动态规划思想)](https://blog.csdn.net/weixin_42100963/article/details/106953141)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值