
一个括号字符串是一个 非空 且只包含 '(' 和 ')' 的字符串。如果下面 任意 条件为 真 ,那么这个括号字符串就是 合法的 。
字符串是 () 。
字符串可以表示为 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,看到这个题,首先想到的是递归,位置i,j的值由i-1,j和i,j-1位置的值决定
2,但是问题来了,每一个位置并不能确定最终是否合法。
3,每一个位置i,j,如果左括号数<0,显然不合法,它最多可以累积i+j+1个左括号,所以这里隐含了第三维变量即累积的括号数。
4,对于每一个位置,当我们遇到左括号,+1;遇到右括号-1;当这个位置的值是负数的时候,没有必要继续了,它已经不合法了
5,当左括号的数>剩余位置数的时候,即:即使以后都是右括号,也没法配对,所以出现这种情况也不合法。
6,因此可以认为:当前位置是否合法是由左边或者上边累积括号数+1或者-1决定的:
如果i,j位置为左括号 dp[i][j][k]=dp[i-1][j][k-1] ||dp[i][j-1][k-1]
如果i,j位置为右括号 dp[i][j][k]=dp[i-1][j][k+1] ||dp[i][j-1][k+1]
7,边界情况dp[0][0][0]=1
8,解:dp[m-1][n-1][0]=0
解法一:dfs加剪枝
func hasValidPath(grid [][]byte) bool {
m, n := len(grid), len(grid[0])
if (m+n)%2 == 0 || grid[0][0] == ')' || grid[m-1][n-1] == '(' { // 剪枝
return false
}
vis := make([][][]bool, m)
for i := range vis {
vis[i] = make([][]bool, n)
for j := range vis[i] {
vis[i][j] = make([]bool, m+n)
}
}
var dfs func(x, y, c int) bool
dfs = func(x, y, c int) bool {
if c > m-x+n-y-1 { // 剪枝:即使后面都是 ')' 也不能将 c 减为 0
return false
}
if x == m-1 && y == n-1 { // 终点
return c == 1 // 终点一定是 ')'
}
if vis[x][y][c] { // 重复访问
return false
}
vis[x][y][c] = true
if grid[x][y] == '(' {
c++
} else if c--; c < 0 { // 非法括号字符串
return false
}
return x < m-1 && dfs(x+1, y, c) || y < n-1 && dfs(x, y+1, c) // 往下或者往右
}
return dfs(0, 0, 0) // 起点
}解法二:dp
func hasValidPath(grid [][]byte) bool {
m, n := len(grid), len(grid[0])
if (m+n)%2 == 0 || grid[0][0] == ')' || grid[m-1][n-1] == '(' {
return false
}
dp := make([][][]bool, m)
for i := range dp {
dp[i] = make([][]bool, n)
for j := range dp[i] {
dp[i][j] = make([]bool, m+n)
}
}
dp[0][0][1] = true
for i := 0; i < m; i++ {
for j := 0; j < n; j ++ {
t := 1
if grid[i][j] == ')' {
t = -1
}
for k := 0; k < m+n; k ++ {
kk := k - t
if kk < 0 || kk >= m+n{
continue
}
if i > 0 {
dp[i][j][k] = dp[i][j][k] || dp[i-1][j][kk]
}
if j > 0 {
dp[i][j][k] = dp[i][j][k] || dp[i][j-1][kk]
}
}
}
}
return dp[m-1][n-1][0]
}