前言
今天复盘两道算法题:一道是困难级别的栈 / 动态规划题「最长有效括号」 ,另一道是中等难度的多维动态规划题「不同路径」。这两道题分别代表了栈的应用和二维 DP 的经典场景,很适合作为面试复习的重点。
一、32. 最长有效括号(困难)
题目描述
给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
核心思路:栈解法(直观好写)
栈是解决这类括号匹配问题的经典数据结构,这道题的关键在于用栈记录 "上一个有效位置":
- 栈底始终保存一个无效位置 (初始为
-1),作为计算长度的基准。 - 遇到
'(',直接压入当前索引; - 遇到
')',弹出栈顶元素:- 如果栈为空,说明当前
')'没有匹配的'(',将当前索引压入作为新的无效位置; - 如果栈不为空,当前有效长度 = 当前索引 - 栈顶索引,更新全局最大值。
- 如果栈为空,说明当前
完整代码(Java)
java
运行
class Solution {
public int longestValidParentheses(String s) {
Deque<Integer> stack = new LinkedList<>();
stack.push(-1);
int maxLen = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
stack.pop();
if (stack.isEmpty()) {
stack.push(i);
} else {
maxLen = Math.max(maxLen, i - stack.peek());
}
}
}
return maxLen;
}
}
坑点与优化
- 栈底的
-1是关键:没有这个初始值,第一次匹配时无法计算长度,会导致数组越界或结果错误。 - 动态规划解法补充 : 定义
dp[i]表示以i结尾的最长有效括号长度。- 当
s[i] == ')'且s[i-1] == '(':dp[i] = dp[i-2] + 2 - 当
s[i] == ')'且s[i-1] == ')'且s[i - dp[i-1] - 1] == '(':dp[i] = dp[i-1] + 2 + dp[i - dp[i-1] - 2]
- 当
- 时间复杂度:栈和 DP 解法都是 O (n),空间复杂度栈解法为 O (n),DP 解法为 O (n)。
二、62. 不同路径(中等)
题目描述
一个机器人位于一个 m x n 网格的左上角(起点),每次只能向下或向右移动一步,请问到达右下角(终点)共有多少条不同的路径?
核心思路:二维动态规划
这是最经典的二维 DP 入门题,核心思想是:
- 定义
dp[i][j]表示到达(i, j)位置的不同路径数。 - 边界条件:第一行和第一列的所有位置都只有 1 条路径(只能一直向右或一直向下)。
- 状态转移方程:
dp[i][j] = dp[i-1][j] + dp[i][j-1](只能从上方或左方移动过来)。
完整代码(Java)
java
运行
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (int j = 0; j < n; j++) {
dp[0][j] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
}
优化与拓展
-
空间优化(一维 DP) : 因为每次更新只需要上一行和当前行的信息,可以将二维数组压缩为一维:
java
运行
class Solution { public int uniquePaths(int m, int n) { int[] dp = new int[n]; Arrays.fill(dp, 1); for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { dp[j] = dp[j] + dp[j-1]; } } return dp[n-1]; } } -
数学方法(组合数) : 从起点到终点,一共需要走
m+n-2步,其中m-1步向下,n-1步向右。路径数就是组合数C(m+n-2, m-1),可以用公式直接计算。