给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
解决方案1,通过栈来解决
常用的括号匹配都是使用栈来解决,通过栈可以很容易的找到栈的匹配。
这个问题,可以分解:
- 连续的括号的求解。
- 分段的括号数求解问题
- 求最大的连接括号数。
连续括号求解
连接括号的求解问题,这个比较容易,可以直接使用栈来实现
/** |
这个代码比较简单,通过统计左括号的数量*2,即可得到总的匹配括号数。
分段的括号数求解问题
刚刚的代码只能统计连接的括号,如果出现不连接的就会出现问题。
怎么解决这个问题呢?我的思路这样子的
只需要加入一个变量来记录下不匹配的位置即可,
那不连续的位置在哪里?
我觉得满足这两个条件:
- 栈为空
- 当前为右括号。
满足这两个条件,将位置记录下来。
/** * 分段连续括号的求解问题 * * @param s * @return */ public int parenthessSegment(String s) { if (null == s || s.length() < 1) { return 0; } char[] data = s.toCharArray(); int length = 0; int badIndex = -1; Stack<Character> stack = new Stack<>(); for (int i = 0; i < data.length; i++) { // 左括号进行压栈操作 if (data[i] == LEFT_PARENTHESS) { stack.push(data[i]); } else { // 在匹配上右括号时,弹出一个左括号,长度++ // 只需要统计左括号,即可*2就可得到总匹配括号数 if (!stack.isEmpty()) { stack.pop(); length++; } else { badIndex = i; } } } return length * 2 - badIndex; } |
当不连接括号出现为右括号时,可以进行正确的验证。
例如:“())(((()))”
但是,如果出现不连续的括号为左括号呢?那是否还能正确匹配呢?
例如: “()((((()))”
答案是不能的,我们的匹配规则是按照左括号压栈操作,右括号进行配对操作。但现在不匹对的是左括号,全部压入了栈。而判断条件是栈为空,并且当前为右括号,条件不满足。需要对此问题进行修正。
我们对栈中的存储进行下修改,之前是存储括号,现在改为存储左括号的索引下标
通过不匹配的位置badindex=-1开始
当栈遍历到索引下标为1时,括号发生配对,索引为0的左括号被弹出栈
现在计算括号数,有此规则当前索引号减去不匹配的位置=括号数
即1-(-1)=2
当遍历到索引为7时,栈中的元素,发生匹配,索引6被弹出,计算7的连接括号数,
有此规则,当前索引号减去栈顶的索引号=连接括号数。
索引7的连接括号数: = 7- 5 = 2
是否后续也有如此规则,再看下索引8
索引8的连接括号数:8-4=4
那用代码实现出来,就是这样子:
/** * 分段连续括号的求解问题 * * @param s * @return */ public int parenthessSegment(String s) { if (null == s || s.length() < 1) { return 0; } char[] data = s.toCharArray(); int length = 0; int badIndex = -1; Stack<Integer> stack = new Stack<>(); for (int i = 0; i < data.length; i++) { // 左括号进行压栈操作 if (data[i] == LEFT_PARENTHESS) { stack.push(i); } else { // 在匹配上右括号时 if (!stack.isEmpty()) { stack.pop(); // 如果还存在元素,则使用当前索引减栈顶索引 if (!stack.isEmpty()) { length = i - stack.peek(); } // 当前已经为空了,说明需要命名用上次出现不匹配的位置. else { length = i - badIndex; } } else { badIndex = i; } } } return length; } |
到现在为止,已经能求解连接的括号数了。
求最大的连接括号数
这个题目的要求是求解最长的匹配括号数。
这个就比较容易了,只需要判断下,留下最大的括号数即可
/** * 分段连续括号的求解问题,最终解决 * * @param s * @return */ public int parenthessLast(String s) { if (null == s || s.length() < 1) { return 0; } char[] data = s.toCharArray(); int length = 0; int badIndex = -1; int maxLengthParenthess = 0; Stack<Integer> stack = new Stack<>(); for (int i = 0; i < data.length; i++) { // 左括号进行压栈操作 if (data[i] == LEFT_PARENTHESS) { stack.push(i); } else { // 在匹配上右括号时 if (!stack.isEmpty()) { stack.pop(); // 如果还存在元素,则使用当前索引减栈顶索引 if (!stack.isEmpty()) { length = i - stack.peek(); } // 当前已经为空了,说明需要命名用上次出现不匹配的位置. else { length = i - badIndex; } if (length > maxLengthParenthess) { maxLengthParenthess = length; } } else { badIndex = i; } } } return maxLengthParenthess; } |