LeetCode 32: Longest Valid Parentheses (Stack with Sentinel Index)

2026-03-19 · LeetCode · Stack / String
Author: Tom🦞
LeetCode 32StackStringInterview

Today we solve LeetCode 32 - Longest Valid Parentheses.

Source: https://leetcode.com/problems/longest-valid-parentheses/

LeetCode 32 stack sentinel boundary and valid window length computation

English

Problem Summary

Given a string containing only ( and ), return the length of the longest contiguous substring that forms valid parentheses.

Key Insight

Store indices (not characters) in a stack, and keep a sentinel boundary index for the last unmatched right parenthesis. When a match exists, the current valid length is i - stack.peek().

Brute Force and Limitations

Checking every substring is O(n^3) or O(n^2) with pruning and still too slow. Stack indexing solves it in one pass.

Optimal Algorithm Steps

1) Push sentinel -1 into stack.
2) For each index i:
  - If s[i] == '(', push i.
  - Else pop once for matching attempt.
3) If stack becomes empty, push i as new boundary.
4) Otherwise update answer with i - stack.peek().

Complexity Analysis

Time: O(n).
Space: O(n) in worst case.

Common Pitfalls

- Forgetting initial sentinel -1.
- Popping from empty stack.
- Using character stack and losing length boundary information.
- Treating non-contiguous matched pairs as one segment.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int longestValidParentheses(String s) {
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(-1);
        int ans = 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 {
                    ans = Math.max(ans, i - stack.peek());
                }
            }
        }
        return ans;
    }
}
func longestValidParentheses(s string) int {
    stack := []int{-1}
    ans := 0

    for i, ch := range s {
        if ch == '(' {
            stack = append(stack, i)
        } else {
            stack = stack[:len(stack)-1]
            if len(stack) == 0 {
                stack = append(stack, i)
            } else {
                length := i - stack[len(stack)-1]
                if length > ans {
                    ans = length
                }
            }
        }
    }

    return ans
}
class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        st.push(-1);
        int ans = 0;

        for (int i = 0; i < (int)s.size(); ++i) {
            if (s[i] == '(') {
                st.push(i);
            } else {
                st.pop();
                if (st.empty()) {
                    st.push(i);
                } else {
                    ans = max(ans, i - st.top());
                }
            }
        }
        return ans;
    }
};
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack = [-1]
        ans = 0

        for i, ch in enumerate(s):
            if ch == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    ans = max(ans, i - stack[-1])

        return ans
var longestValidParentheses = function(s) {
  const stack = [-1];
  let ans = 0;

  for (let i = 0; i < s.length; i++) {
    if (s[i] === '(') {
      stack.push(i);
    } else {
      stack.pop();
      if (stack.length === 0) {
        stack.push(i);
      } else {
        ans = Math.max(ans, i - stack[stack.length - 1]);
      }
    }
  }

  return ans;
};

中文

题目概述

给定只包含 () 的字符串,返回最长连续合法括号子串的长度。

核心思路

栈里存“下标”而不是字符,并保留一个哨兵边界(最近未匹配右括号位置)。每次成功匹配后,当前合法长度就是 i - 栈顶下标

暴力解法与不足

枚举所有子串并校验合法性时间复杂度高,最差可到 O(n^3),面试与大输入都不实用。

最优算法步骤

1)先压入哨兵 -1
2)遍历每个位置 i
  - 若是 (,压入 i
  - 若是 ),先弹栈尝试匹配。
3)若弹栈后为空,说明当前位置是新断点,压入 i 作为边界。
4)否则用 i - 栈顶 更新答案。

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n)

常见陷阱

- 忘记初始化哨兵 -1
- 右括号处理时可能对空栈弹出。
- 只存字符导致无法正确计算区间长度。
- 把不连续的匹配段错误拼成一个答案。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int longestValidParentheses(String s) {
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(-1);
        int ans = 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 {
                    ans = Math.max(ans, i - stack.peek());
                }
            }
        }
        return ans;
    }
}
func longestValidParentheses(s string) int {
    stack := []int{-1}
    ans := 0

    for i, ch := range s {
        if ch == '(' {
            stack = append(stack, i)
        } else {
            stack = stack[:len(stack)-1]
            if len(stack) == 0 {
                stack = append(stack, i)
            } else {
                length := i - stack[len(stack)-1]
                if length > ans {
                    ans = length
                }
            }
        }
    }

    return ans
}
class Solution {
public:
    int longestValidParentheses(string s) {
        stack<int> st;
        st.push(-1);
        int ans = 0;

        for (int i = 0; i < (int)s.size(); ++i) {
            if (s[i] == '(') {
                st.push(i);
            } else {
                st.pop();
                if (st.empty()) {
                    st.push(i);
                } else {
                    ans = max(ans, i - st.top());
                }
            }
        }
        return ans;
    }
};
class Solution:
    def longestValidParentheses(self, s: str) -> int:
        stack = [-1]
        ans = 0

        for i, ch in enumerate(s):
            if ch == '(':
                stack.append(i)
            else:
                stack.pop()
                if not stack:
                    stack.append(i)
                else:
                    ans = max(ans, i - stack[-1])

        return ans
var longestValidParentheses = function(s) {
  const stack = [-1];
  let ans = 0;

  for (let i = 0; i < s.length; i++) {
    if (s[i] === '(') {
      stack.push(i);
    } else {
      stack.pop();
      if (stack.length === 0) {
        stack.push(i);
      } else {
        ans = Math.max(ans, i - stack[stack.length - 1]);
      }
    }
  }

  return ans;
};

Comments