LeetCode第32题思悟——最长有效括号(longest-valid-parentheses)
知识点预告
- 栈的使用方法;
- 长度的计算方法;
- 数组的妙用;
题目要求
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的思路
输入字符转中一共有两种符号,左括号和右括号;左括号意味着未来有有可能出现右括号与之配对,增加有效长度;出现右括号意味着需要一个左括号与之配对;
从遍历的角度来看,先遇到的左括号与后遇到的右括号匹配;所以我们需要使用栈;遇到左括号,说明可能开始一段新的匹配,遇到右括号,说明我么结束了一段匹配;
开始新的匹配,意味着需要重新记录长度;结束一段匹配,意味着要更新最长有效括号的长度;
我们使用栈来存储当前有效括号的长度:遇到左括号,压入0(不管之前什么情况,因为遇到左括号,就要重新开始);遇到右括号,弹出数字,加2,然后和栈顶数字相加,表示完成匹配且融合;
最后,检查栈中数据即可找到最大值;
public int longestValidParentheses(String s) {
if(s==null||s.trim().equals("")){
return 0;
}
char[] chars=s.toCharArray();
LinkedList<Integer> buffer=new LinkedList<>();
int maxLength=0;
int left=0;
Integer topValue;
Integer newTopValue;
for(char currentChar:chars){
if(currentChar=='('){
buffer.push(0);
left++;
}else{//出现右括号
if((topValue=buffer.peek())!=null){
buffer.poll();
newTopValue=buffer.peek();
if(newTopValue!=null){//还可以继续扩展
buffer.poll();
buffer.push(newTopValue+2+topValue);
left--;
}else{
if(left!=0) {
buffer.push(2 + topValue);
left--;
}else{//无法继续扩展,需要比较
if(topValue>maxLength){
maxLength=topValue;
}
}
}
}
}
}
while((topValue=buffer.peek())!=null){
buffer.poll();
if(topValue>maxLength){
maxLength=topValue;
}
}
return maxLength;
}
优秀解法
//解法A
public int longestValidParentheses(String s) {
int max = 0;
Stack<Integer> stack = new Stack<Integer>();
stack.push(-1);
int temp = 0;
for(int i = 0;i < s.length();i++){
if(s.charAt(i) == '('){
stack.push(i);
}else{
stack.pop();
if(stack.empty()){
stack.push(i);
}else{
max = Math.max(i-stack.peek(), max);
}
}
}
return max;
}
//解法B
public int longestValidParentheses(String s) {
int[] dp=new int[s.length()];
if(s.length()==0){
return 0;
}
dp[0]=0;
int max=0;
for(int i=1;i<s.length();i++) {
if(s.charAt(i)==')'&&(i-dp[i-1]-1>=0)&&s.charAt(i-dp[i-1]-1)=='(') {
dp[i]=dp[i-1]+2;
if(i-dp[i]>=0) {
dp[i]+=dp[i-dp[i]];
}
}else {
dp[i]=0;
}
max=Math.max(max, dp[i]);
}
return max;
}
差异分析
解法A和解法B均使用了栈这一数据结构,不同的是,我使用LinkedList作为栈,解法A使用Stack实现栈,而解法B使用数组实现栈;
使用数组的一大好处就是效率高,但是一些位置计算却需要自己处理,我们从解法B的代码中也可以看得出;
解法A中,栈顶元素的含义是上一次不匹配的下标;当遇到左括号时,不匹配,所以入栈下标;当遇到右括号时,可以抵消一次不匹配,那么当前位置和上一次不匹配位置之间的距离就是最长的有效距离了;
注意首次入栈的-1,因为遇到右括号时,流程如下:抵消一次不匹配,然后计算与上一次不匹配点的距离。那么当字符串完全匹配时,上一次不匹配点本身是不存在的,但是为了统一计算,加入这个-1,就刚刚好了;
解法B使用数组来实现栈的效果;dp[i]的含义是以下标为i的点作为右终点的最长有效括号长度;那么i-dp[i]的意义则是有效括号开始下标的前一个位置;a(((())))就是当i到了最右边时,a的下标;为的是合并有效括号,得到更长的长度;
知识点
- 栈的使用方法;
- 长度的计算方法;
- 数组的妙用;