先看代码:
public class newSolution {
public int longestValidParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int start = 0;
int maxLen = 0;
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
if (!stack.isEmpty()) {
// start 用于记录合法的第一个左括号的位置
stack.pop();
// 如果此时栈空了,说明可以匹配的都已经匹配完成了,这时候就应该
// 算一算总共的长度,然后和maxlen 比较
if (stack.isEmpty()) {
maxLen = Math.max(i - start + 1, maxLen);
} else {
// 如果此时栈没有空,那么就按照正常来进行计算然后与maxlen进行比较
maxLen = Math.max(i - stack.peek(), maxLen);
}
} else {
start = i + 1;
}
}
}
return maxLen;
}
}
解题过程:
设置start = 0; // 表示合法左括号起始的位置
- 通过循环来正向遍历每个字符
- 如果是 “(” 就压入栈中
- 否则:
- 如果栈不空,弹出一个元素,因为这个题中只有 “(” 和 “)” 两种,所以直接弹出就可以
1. 弹出后栈如果空了,就说明从start 开始,到 i 结束,这期间的括号的合法且封闭的。如图:
i 到达所示位置时,栈弹出 start 位置的(,然后栈就空了。此时可以看到,合法的括号长度为i - start +1,然后与maxLen进行比较。
2. 如果栈不空,就将 i - stack.peek() 与 maxLen比较即可(这里自己画画图还是很好理解的。例外就是为什么将 i - stack.peek 和 i - start +1 来分开进行比较,这一点自己画画图也可以看出来)。 - 如果栈空了,就将 start = i + 1。什么时候栈空了呢?接着上面那张图说,就是 i 向后移动一个位置,发现是 " )" ,因此不压入栈,之后的判断就发现栈空了。 为什么让 start = i + 1呢?因为如果未压栈,说明此时 i 所指向的是 “)”,但是start 的作用是记录合法的左括号起始位置,所以要跳过 i (start 的使用是比较巧妙的地方)
- 如果栈不空,弹出一个元素,因为这个题中只有 “(” 和 “)” 两种,所以直接弹出就可以