DeepSeek LeetCode 2267.检查是否有合法括号字符串路径 public boolean hasValidPath(char[][] grid)
这是一道检查网格中是否存在合法括号字符串路径的问题。我会逐步分析并给出实现。
问题分析
我们需要从 (0,0) 到 (m-1, n-1) 找一条路径,使得路径上的字符组成的括号字符串是合法的。
关键难点:网格大小可能达到 100×100,直接 BFS/DFS 会超时,需要状态剪枝。
核心思路
由于括号需要匹配,任何时候 左括号数 >= 右括号数,且最终左右括号数相等。路径长度固定为 m+n-1,所以:
· 长度必须是偶数(否则不能完全匹配)
· 左右括号数量各占一半
状态设计:(i, j, balance) 表示到达 (i,j) 时未匹配的左括号数
重要观察:
· balance 最大不会超过路径长度的一半(最多 (m+n-1)/2)
· 同一 (i,j,balance) 只需访问一次
代码实现
```java
class Solution {
public boolean hasValidPath(char[][] grid) {
int m = grid.length;
int n = grid[0].length;
// 路径长度必须是偶数
if ((m + n - 1) % 2 != 0) return false;
// 起点和终点必须是括号匹配的可能起点/终点
if (grid[0][0] == ')' || grid[m-1][n-1] == '(') return false;
// 使用三维visited数组进行剪枝
Boolean[][][] memo = new Boolean[m][n][(m+n)/2 + 1];
return dfs(grid, 0, 0, 0, memo);
}
private boolean dfs(char[][] grid, int i, int j, int balance, Boolean[][][] memo) {
int m = grid.length;
int n = grid[0].length;
// 更新balance
if (grid[i][j] == '(') {
balance++;
} else {
balance--;
}
// 剪枝:balance不能为负,且不能超过剩余路径能匹配的最大值
if (balance < 0) return false;
if (balance > (m + n - i - j - 1)) return false;
// 到达终点
if (i == m-1 && j == n-1) {
return balance == 0;
}
// 检查缓存
if (memo[i][j][balance] != null) {
return memo[i][j][balance];
}
// 向下或向右移动
boolean result = false;
if (i + 1 < m) {
result = dfs(grid, i+1, j, balance, memo);
}
if (!result && j + 1 < n) {
result = dfs(grid, i, j+1, balance, memo);
}
return memo[i][j][balance] = result;
}
}
```
关键优化点
1. 长度奇偶性检查:提前排除不可能的情况
2. 起点终点检查:起点不能是 ),终点不能是 (
3. balance上限:balance 最大不会超过剩余未访问格子数(这些格子最多能提供的左括号数)
4. 记忆化搜索:避免重复状态
复杂度分析
· 时间复杂度:O(m × n × (m+n)),但实际剪枝后远小于此
· 空间复杂度:O(m × n × (m+n))
这个解法能通过 LeetCode 的测试用例。
更多推荐


所有评论(0)