【C++动态规划 合法括号】2267. 检查是否有合法括号字符串路径|2084

本文涉及知识点

C++动态规划

LeetCode2267. 检查是否有合法括号字符串路径

一个括号字符串是一个 非空 且只包含 '(' 和 ')' 的字符串。如果下面 任意 条件为 真 ,那么这个括号字符串就是 合法的 。

字符串是 () 。

字符串可以表示为 AB(A 连接 B),A 和 B 都是合法括号序列。

字符串可以表示为 (A) ,其中 A 是合法括号序列。

给你一个 m x n 的括号网格图矩阵 grid 。网格图中一个 合法括号路径 是满足以下所有条件的一条路径:

路径开始于左上角格子 (0, 0) 。

路径结束于右下角格子 (m - 1, n - 1) 。

路径每次只会向 下 或者向 右 移动。

路径经过的格子组成的括号字符串是 合法 的。

如果网格图中存在一条 合法括号路径 ,请返回 true ,否则返回 false 。

示例 1:

输入:grid = [["(","(","("],[")","(",")"],["(","(",")"],["(","(",")"]]

输出:true

解释:上图展示了两条路径,它们都是合法括号字符串路径。

第一条路径得到的合法字符串是 "()(())" 。

第二条路径得到的合法字符串是 "((()))" 。

注意可能有其他的合法括号字符串路径。

示例 2:

输入:grid = [[")",")"],["(","("]]

输出:false

解释:两条可行路径分别得到 "))(" 和 ")((" 。由于它们都不是合法括号字符串,我们返回 false 。

提示:

m == grid.length

n == grid[i].length

1 <= m, n <= 100

grid[i][j] 要么是 '(' ,要么是 ')' 。

合法括号+动态规划

合法括号的另一种表达方式:左括号分值1,右括号分值-1。s的分值0,任意前缀的分值都为0 是合法括号。

动态规划的状态表示

dp[r][c][v] ,以grid[r][c]结尾,分值为v的方案是否存在。空间复杂度:O(nm(n+m))

动态规划的填表顺序

r=0 to m-1 c = 0 to n-1 v =0 to m+n-1

动态规划的转移方程

dp[r][c]不成立,忽略。

v1 =v + grid[r][c+1]的值。如果v1 < 0,忽略。

右移:dp[r][c+1][v1] = true;

下移类似

单个状态转移时间复杂度:O(1)

时间复杂度:O(mn(m+n))

动态规划的初始值

dp[0][0][1]=true,其它全false。

如果grid[0][0]是反括号,返回false

动态规划的返回值:

dp.back().back()[0]

代码

核心代码

cpp 复制代码
class Solution {
		public:
			bool hasValidPath(vector<vector<char>>& grid) {
				if (')' == grid[0][0])return false;
				const int R = grid.size();
				const int C = grid[0].size();
				const int K = R + C;
				auto S = [&](const char& ch) {return ('(' == ch) ? 1 : -1; };				
				vector<vector<vector<bool>>> dp(R, vector<vector<bool>>(C,vector<bool>(K)));
				dp[0][0][1] = true;
				auto Add = [&](int r, int c, int kPre) {
					if (r >= R)return;
					if (c >= C)return;
					const int k = kPre + S(grid[r][c]);
					if (k < 0)return;
					if (k >= K)return;
					dp[r][c][k] = true;
				};
				for (int r = 0; r < R; r++) {
					for (int c = 0; c < C; c++) {
						for (int k = 0; k < R + C; k++) {
							if (dp[r][c][k]) {
								Add(r + 1, c, k);
								Add(r, c+1, k);
							}
						}
					}
				}
				return dp.back().back()[0];
			}
		};

单元测试

cpp 复制代码
vector<vector<char>> grid;
		TEST_METHOD(TestMethod11)
		{
			grid = { {'(','(','('},{')','(',')'},{'(','(',')'},{'(','(',')'} };
			auto res = Solution().hasValidPath(grid);
			AssertEx(true, res);
		}
		TEST_METHOD(TestMethod12)
		{
			grid = { {')',')'},{'(','('} };
			auto res = Solution().hasValidPath(grid);
			AssertEx(false, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关推荐
c-c-developer1 小时前
C++Primer const限定符
c++
不是仙人的闲人4 小时前
数据结构之栈和队列
数据结构·c++
重生之我是数学王子4 小时前
内核链表 例题 C语言实现
linux·c++
salsm10 小时前
使用 C++ 和函数式编程构建高效的 AI 模型
c++·人工智能
程序猿(雷霆之王)10 小时前
C++——继承
开发语言·c++
xianwu54310 小时前
mysql入门篇
开发语言·网络·c++·git
qq_140303414412 小时前
数据结构9.3 - 文件基础(C++)
数据结构·c++
Lenyiin13 小时前
第431场周赛:最长乘积等价子数组、计算字符串的镜像分数、收集连续 K 个袋子可以获得的最多硬币数量、不重叠区间的最大得分
c++·算法·leetcode·周赛·lenyiin
轻口味13 小时前
【每日学点鸿蒙知识】多个har依赖、指定编译架构、ArkTS与C++互相调用
c++·华为·harmonyos
智能与优化14 小时前
动态库dll与静态库lib编程4:MFC规则DLL讲解
开发语言·c++·mfc