LeetCode 最长有效括号
@author:Jingdai
@date:2020.10.10
题目描述(32题)
给定一个只包含
'('
和')'
的字符串,找出最长的包含有效括号的子串的长度。
示例输入
")()())"
示例输出
4
解释
最长有效括号子串为 "()()"
思路
方法1 dp
动态规划,建立一个长度等于字符串长度的数组
dp[]
,数组dp[i]
的值代表以i
结尾的子串的最长有效括号长度。
初始条件
很明显,初始条件
dp[0] = 0
。求解过程
当
s.charAt(i) == '('
时,dp[i] = 0
。当
s.charAt(i) == ')'
且s.charAt(i-1) == '('
时,dp[i] = dp[i-2] + 2
。如下图。
当
s.charAt(i) == ')'
且s.charAt(i-1) == ')'
时,若s.charAt(i-1-dp[i-1]) == '('
,则dp[i] = dp[i-1] + 2 + dp[i-1-dp[i-1] - 1]
。如下图。注意事项
注意边界条件判断,即下标不要越界。
代码见下面。
方法2 stack
首先你会发现一个有效括号的子串的任意位置处,它前面(包括自己)的
'('
数总是大于等于')'
数,而当')'
数多的时候,它一定不是有效的括号串。利用这个性质,操作栈stack
。遍历字符串,如果遇到
'('
,将它的下标入栈;如果遇到')'
,表示可以弹出一个'('
与它配对,则弹栈,如果栈不为空,表示正确的构造了一个有效括号串,则以该下标结尾的有效子串长度为当前下标减去栈顶元素。如果栈为空,表示')'
多了,不能成为有效的括号串,则将当前的下标入栈,用作下一次使用。为了整个遍历的统一不用分情况讨论,在遍历前首先将一个 -1 压栈,表示最初有一个
')'
在栈中。代码见下面。方法3 正反向遍历
思路还是和栈有点类似,就是一个有效括号的子串的任意位置处,它前面(包括自己)的
'('
数总是大于等于')'
数,而当')'
数多的时候,它一定不是有效的括号串。首先从头遍历字符串,记录一个
left
和一个right
表示'('
和')'
的数目。当right > left
时,表示这里已经不可能有有效的括号串了,将left
和right
置为 0 继续进行遍历。当left == right
时,代表已经找到了一个有效的括号串。更新长度。但是这种会漏掉一种情况,就是
'('
一直大于')'
的情况,就会出现无法找到有效的括号串,比如"(()"
,所以在利用同样的思路,从尾部开始遍历,这样就是当'('
多的时候,它一定不是一个有效的括号串,可以将第一次遍历漏掉的情况考虑到。当right < left
时,将left
和right
置为 0 继续进行遍历。当left == right
时,代表已经找到了一个有效的括号串。更新长度。代码见下面。
代码
方法1
public int longestValidParentheses(String s) { int[] dp = new int[s.length()]; int longestLen = 0; for (int i = 1; i < s.length(); i++) { if (s.charAt(i) == ')') { if (s.charAt(i-1) == '(') { dp[i] = i-2 >= 0 ? (dp[i-2] + 2) : 2; // process when i = 1 longestLen = dp[i] > longestLen ? dp[i] : longestLen; } else if (s.charAt(i-1) == ')' && i-1-dp[i-1] >= 0 && s.charAt(i-1-dp[i-1]) == '(') { if (i-1-dp[i-1]-1 >= 0) { dp[i] = dp[i-1] + 2 + dp[i-1-dp[i-1]-1]; } else { dp[i] = dp[i-1] + 2; } longestLen = dp[i] > longestLen ? dp[i] : longestLen; } } } return longestLen; }
方法2
public int longestValidParentheses(String s) { LinkedList<Integer> stack = new LinkedList<>(); stack.add(-1); int longestLen = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '(') { stack.addFirst(i); } else { stack.poll(); if (stack.size() == 0) { stack.addFirst(i); } else { longestLen = longestLen > i - stack.getFirst() ? longestLen : i - stack.getFirst(); } } } return longestLen; }
方法3
public int longestValidParentheses(String s) { int left = 0; int right = 0; int longestLen = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '(') { left++; } else { right++; } if (left == right) { longestLen = longestLen > 2 * left ? longestLen : 2 * left; } else if (right > left) { left = 0; right = 0; } } left = 0; right = 0; for (int i = s.length() - 1; i >= 0; i--) { if (s.charAt(i) == '(') { left++; } else { right++; } if (left == right) { longestLen = longestLen > 2 * left ? longestLen : 2 * left; } else if (left > right) { left = 0; right = 0; } } return longestLen; }