C++ 版本
class Solution {
public:
int longestValidParentheses(string s) {
if (s.empty()) return 0;
int res = 0;
stack<int> stk;
stk.push(-1); // 处理边界情况
for (int i = 0; i < s.size(); i++) {
if (s[i] == '(') {
stk.push(i); // 记录左括号索引
} else {
stk.pop(); // 弹出匹配的左括号索引
if (stk.empty()) {
stk.push(i); // 记录新的无效起点
} else {
res = max(res, i - stk.top());
}
}
}
return res;
}
};
思路解析
1. 为什么使用栈?
• 我们需要找到最长的有效括号子串,即括号可以正确匹配的最长子序列。
• 栈(Stack) 是一个 LIFO(后进先出) 的数据结构,非常适合匹配括号问题。
2. 如何使用栈?
• 栈中存储的是索引,而不是字符本身。
• 维护一个初始值 -1 作为基准,以便计算子串长度。
具体运行步骤
示例 1
s = "(()())"
Step 1: 初始化
栈:[-1] (用于基准计算)
res = 0
Step 2: 遍历 s
i | s[i] | 操作 | 栈内容 | 计算 res |
---|---|---|---|---|
0 | ( | 入栈 (存索引 0) | [-1,0] | 0 |
1 | ( | 入栈 (存索引 1) | [-1,0,1] | 0 |
2 | ) | 出栈 (匹配 1) | [-1,0] | 2-0=2 |
3 | ( | 入栈 (存索引 3) | [-1,0,3] | 2 |
4 | ) | 出栈 (匹配 3) | [-1,0] | 4-0=4 |
5 | ) | 出栈 (匹配 0) | [-1] | 5-(-1)=6 |
最终结果
res = 6
示例 2
s = ")()())"
Step 1: 初始化
栈:[-1] (用于基准计算)
res = 0
Step 2: 遍历 s
i | s[i] | 操作 | 栈内容 | 计算 res |
---|---|---|---|---|
0 | ) | 栈空,更新基准 0 | [0] | 0 |
1 | ( | 入栈 (存索引 1) | [0,1] | 0 |
2 | ) | 出栈 (匹配 1) | [0] | 2-0=2 |
3 | ( | 入栈 (存索引 3) | [0,3] | 2 |
4 | ) | 出栈 (匹配 3) | [0] | 4-0=4 |
5 | ) | 出栈 (匹配 0) | [] | 栈空,更新基准 5 |
最终结果
res = 4
复杂度分析
操作 | 时间复杂度 | 空间复杂度 |
---|---|---|
遍历 s | O(n) | O(n) |
计算最长有效括号 | O(1) | O(n) |
总复杂度 | O(n) | O(n) |
总结
✅ 栈方法(O(n) 时间)
• 核心思想:栈存储索引,利用匹配索引计算最长有效子串长度。
• 初始化:先存入 -1,作为基准。
• 遍历 s:
• ( 入栈(存索引)。
• ) 出栈:
• 若栈不空:计算最长有效子串 i - stack.top()。
• 若栈空:存入 i 作为新的基准点。
📌 相比暴力解法(O(n²))和 DP 方法(O(n)),栈方法的实现更加直观,且空间效率更优!
如果有进一步的优化需求,比如 O(n) O(1) 解法,可以使用双指针扫描法,如果你感兴趣,我可以介绍给你!🚀