题目描述:
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
这道题最容易想到的就是暴力破解法,把输入字符串s里面的所有连续的子串都拿出来,判断这个子串是不是有效的,如果有效就判断其长度。当所有子串都被判断了一遍,一定会找到一个最长有效括号的长度。但是这个方法毫无疑问是比较耗时,如果输入的s很长的时候,摆脱不了执行超时的命运(至少我就尝试了很多遍超时),所以需要另寻出路。
之前在有做过一道题,判断输入的字符串是不是有效的括号。那道题里面用到了堆栈,遇到了左半边的括号就推进堆栈里,遇到右边的括号就推出堆栈里的内容,看是否能够和这个右半边的括号配对,如果能配对就继续执行,不能配对就直接返回配对失败了。
应用到这道题里面,可以创建一个堆栈,遇到 ‘(’ 时,就把当前 ‘(’ 的位置推进堆栈,当遇到 ‘)’ 时就弹出堆栈顶部的内容,前面一个 ‘(’ 就成功配对了,在还没读进下一个字符进行判断是,如今堆栈顶部的内容就是一个无效的括号(至少是目前位置是无效的),用当前的位置减去堆栈顶部的内容就能得到有效括号的长度了。同时,为了防止字符串的第一个字符是 ‘)’ ,在所有步骤之前在堆栈里放一个-1,防止执行pop()出错,同样的,当执行到一定的阶段的时候,有可能遇到 ‘)’ 比 ‘(’ 多,也就是说弹出的次数比推进的次数错,如果不采取措施一定会执行出错,所以在遇到 ‘)’ 弹出堆栈的内容是,判断堆栈是否为空,如果堆栈为空,则推进当前 ‘)’ 所在的位置(同时这个 ‘)’ 一定是无效的!!)。当遍历完字符串,一定会找出一个最长有效括号的长度。
代码(Java):
public class Solution {
public static void main(String[] args) {
String s = "(()";
// System.out.println(s.charAt(s.length()-1));
System.out.println(longestValidParentheses(s));
}
public static int longestValidParentheses(String s) {
int maxans = 0; //存放最长有效括号的长度
Stack<Integer> stack = new Stack<>(); //创建一个新的栈来处理,遍历字符串里面的字符,当遇到'('时,推进当前的位置,遇到')'时,弹出栈最顶的内容(与当前的')'配对),并推进当前位置的坐标
//这样有效的括号(成对)都是一进一出的,堆栈最顶部的内容就是找到最近一个无效(至少是还不确定有效)的括号,与当前的位置相减就得到有效括号长度
stack.push(-1); //首先往栈里推进一个-1,防止字符串的第一个字符就是')',堆栈为空,执行pop出错
for (int i = 0; i < s.length(); i++) { //遍历字符串里面的每一个字符
if (s.charAt(i) == '(') { //当遇到了'('时,推进当前的位置
stack.push(i);
} else { //如果遇到')',推出栈最顶端的内容
stack.pop();
if (stack.empty()) { //如果堆栈里是空的,则推进当前')'的位置,和一开始推进-1一样道理
stack.push(i);
} else {
maxans = Math.max(maxans, i - stack.peek()); //目前位置最长的有效长度
}
}
}
return maxans;
}
}