携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,点击查看活动详情
题目描述
给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
示例 1:
输入:s = "(()" 输出:2 解释:最长有效括号子串是 "()" 示例 2:
输入:s = ")()())" 输出:4 解释:最长有效括号子串是 "()()" 示例 3:
输入:s = "" 输出:0
提示:
- 0 <= s.length <= 3 * 104
- s[i] 为 '(' 或 ')'
解题思路
有效括号是指一个'('一定有一个')'与其配对,给定字符串s,从s中找到最长的有效括号子串并返回。
看见符号匹配,就要想到栈。因为符号匹配一般是前后匹配,栈的特点就是先进后出,所以可以用来解答类似题目;
一个有效的括号字符串肯定是以')'结尾的,再加上栈的先进后出的特性。
首先确定栈中存储的元素,因为这道题求的是最长的有效括号,即要求的肯定是连续的最长的,所以需要获得连续最长子串的结尾下标和开始下标;
结尾下标可以取一个有匹配左括号'('的的右括号的下标,开始下标就是这个连续弹出的字符串的开始位置。
所以栈中应该存储两类元素,一种是左括号(方便遇见右括号之后弹出);
一种是未被匹配的元素,包括左括号和右括号。
综合来说就是所有的左括号和匹配时栈中没有匹配的左括号的右括号的位置;
遍历字符串s,遇到左括号'('即将当前位置的坐标放入栈中,遇到右括号')'则从栈中弹出一个对应的左括号'(',如果没有对应的左括号,则将当前右括号的坐标也一起放入栈中(此时代表一个新的子串开始了);
需要注意的是,由于子串的位置是靠栈顶的元素坐标和当前右括号的坐标决定的,当第一个元素为左括号时,如果它被匹配掉了,栈顶就没有元素了,所以为了方便处理,这里也可以加一个类似哨兵节点的值,初始时向栈中加入-1,减少复杂度。
代码实现
public static int longestValidParentheses(String s) {
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int max = 0;
int length = s.length();
for (int i=0; i< length; i++) {
if (s.charAt(i) == '(') {
// 放入stack
stack.push(i);
} else {
// 从stack中取第一个元素
Integer before = stack.peek();
if (before != -1 && s.charAt(before) == '(') {
stack.pop();
// 计算最大值
max = Math.max(max,i-stack.peek());
} else {
// 未被匹配的右括号,将当前元素也放入stack中
stack.push(i);
}
}
}
return max;
}