此题 看着简单,其实挺难的。LeetCode困难题目。常规想法并不能解决
【题目】
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
【注意】如果栈为空的话,peek会报错,不会返回null。
Stack<Character> stack = new Stack<>();
Character c = stack.peek();
报错
Exception in thread "main" java.util.EmptyStackException
at java.util.Stack.peek(Stack.java:102)
at 牛客刷题.LeetCode.栈.longest_valid_parentheses.Solution.longestValidParentheses(Solution.java:21)
at 牛客刷题.LeetCode.栈.longest_valid_parentheses.Solution.main(Solution.java:11)
原来考虑用栈压入字符’(‘和’)’,发现存在问题,不能讲前面的括号连起来。
比如()(()
,用下面的做法怎么判断是不是要把第一组括号也算进来呢。如果是这种情况,第三个符号没有对应的右括号了,自然就没有和第一组连起来。
如果以下情况()(())
,就要连起来。
解决方法,换一种思路,压入栈的不是单纯的’(‘,这个栈中其实只会压入’(‘,是种浪费。可以压入字符所在的下标,多了下标信息,问题就可以解下去。
package 牛客刷题.LeetCode.栈.longest_valid_parentheses;
import java.util.LinkedList;
import java.util.Stack;
/**
* Created by Administrator on 2018/5/26 0026.
*/
public class Solution {
public static void main(String[] args) {
//String s = "(()()";
String s = "()(()";
System.out.println(longestValidParentheses(s));
}
public static int longestValidParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] chars = s.toCharArray();
int res = 0, max = 0, last = 0;
Stack<Character> stack = new Stack<>();
for (int i =0; i < chars.length; i++) {
if (chars[i] == '(' ) {
if (stack.size() == 0) {
last = max;
}
stack.push('(');
} else {
if (stack.size() != 0 && stack.peek() == '('){
last++;
max = last;
stack.pop();
} else {
last = 0;
}
res = Math.max(res, max);
max = 0;
}
}
return res * 2;
}
}
写的代码在(()()
测试用例下出错
对应输出应该为:
4
你的输出为:
2
原因是我在考虑局部的括号组的时候没有吧相连的括号考虑进来。
不光在stack为空的时候,要和前面的括号组连起来。
相邻的括号组要直接连起来的。
public static int longestValidParentheses(String s) {
char[] chars = s.toCharArray();
LinkedList<Integer> stack = new LinkedList<>();
int start = 0;
int res = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '(') {
stack.push(i);
} else {
if (stack.size() == 0) {
start = i + 1;
} else if (stack.size() == 1){
stack.pop();
res = Math.max(res, i - start + 1);
} else {
res = Math.max(res, i - stack.pop() +1);
}
}
}
return res;
}
注:
这道题用动态规划解也可以
dp[i]是以chars[i-1]字符为结尾,能组成的最大括号组合数。
dp[i+1]根据char[i]的具体的括号类型得来,递推详见代码。
如果字符是'('
dp[i+1]为0。
如果字符是')'
根据chars[i-1]是左还是右括号分情况讨论
注意如果配对了,要考虑配对前面的括号组合连起来的。代码很容易出错。
详情看代码longestValidParentheses()方法。
package 牛客刷题.LeetCode.栈.longest_valid_parentheses;
import java.util.LinkedList;
import java.util.Stack;
/**
* Created by Administrator on 2018/5/26 0026.
*/
public class Solution {
public static void main(String[] args) {
System.out.println(longestValidParentheses("(()()")); //4
System.out.println(longestValidParentheses("()(()")); //2
System.out.println(longestValidParentheses("((())()")); //6
System.out.println(longestValidParentheses("())")); //2
System.out.println(longestValidParentheses("()(())")); //6
}
//错误的解法
public static int longestValidParentheses1(String s) {
if(s==null || s.length()==0)
return 0;
LinkedList<Integer> stack = new LinkedList<Integer>();
int start = 0;
int max = 0;
for(int i=0;i<s.length();i++)
{
if(s.charAt(i)=='(')
{
stack.push(i);
}
else
{
if(stack.isEmpty())
{
start = i+1;
}
else
{
stack.pop();
max = stack.isEmpty()?Math.max(max,i-start+1): Math.max(max,i-stack.peek());
}
}
}
return max;
}
//考虑动态规划方法
public static int longestValidParentheses(String s) {
if (s == null || s.length() == 0) {
return 0;
}
char[] chars = s.toCharArray();
int[] dp = new int[s.length() + 1];
int max = 0;
dp[0] = 0;
dp[1] = 0;
for (int i = 1; i < s.length(); i++) {
if (chars[i] == ')') {
if (chars[i-1] == '(') {
dp[i+1] = dp[i-1] + 2;
} else {
if (i-dp[i] -1 >= 0 && chars[i - dp[i] -1] == '(') {
dp[i + 1] = dp[i] + 2 + dp[i- dp[i] -1];
} else {
dp[i+1] = 0;
}
}
} else {
dp[i+1] = 0;
}
max = Math.max(max, dp[i+1]);
}
return max;
}
//栈的解法,存入下标
public static int longestValidParentheses2(String s) {
char[] chars = s.toCharArray();
LinkedList<Integer> stack = new LinkedList<>();
int start = 0;
int res = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '(') {
stack.push(i);
} else {
if (stack.size() == 0) {
start = i + 1;
} else if (stack.size() == 1){
stack.pop();
res = Math.max(res, i - start + 1);
} else {
stack.pop();
res = Math.max(res, i - stack.peek());
}
}
}
return res;
}
}