题目
给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”
(以下题解思路来自leetcode官方)
思路一 使用栈
首先将-1加入栈(-1用于计算字符串的长度,比如“(()))” )。我们从前开始遍历字符串,遇到"(",将其的索引压栈,遇到")",直接出栈,然后将当前索引减去当前栈顶元素得到一个值,与max进行比较,留下最大的那个。
算法示例(以")()())"为例):
思路一代码
public class problem32 {
public int longestValidParentheses(String s) {
int max=0;
Stack<Integer> st=new Stack<Integer>();
st.push(-1);
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='('){
st.push(i);
}else{
st.pop();
if(st.isEmpty()){
st.push(i);
}else{
max=Math.max(max, i-st.peek());
}
}
}
return max;
}
public static void main(String[] args) {
problem32 pro=new problem32();
System.out.println(pro.longestValidParentheses(")()())"));
}
}
思路二 动态规划
这个问题可以通过动态规划解决。我们定义一个 dp 数组,其中第 i个元素表示以下标为 i 的字符结尾的最长有效子字符串的长度。我们将dp 数组全部初始化为 0 。现在,很明显有效的子字符串一定以‘)’结尾。这进一步可以得出结论:以 “(” 结尾的子字符串对应的 dp 数组位置上的值必定为 0 。所以说我们只需要更新“)”在 dp 数组中对应位置的值。
以下是dp数组的求解过程:
1、s[i]=")"&&s[i-1]="(“时,也就是形如“…()”
dp[i]=dp[i-2]+2;
其中dp[i-2]表示“(”前面的有效子串长度,2表示新的子串”()"的长度
2、s[i]=")"&&s[i-1]=")“时,也就是形如“…))”
dp[i]=dp[i-1]+dp[i-dp[i-1]-2]+2;
其中dp[i-1]表示第一个”)“前面的有效子串长度,而2表示新加入的子串”()"的长度,dp[i-dp[i-1]-2]表示这个部分:
这个部分((…))
3、s[i]="(",跳过
其实里面还有很多细节的东西,当有些是在考虑算法的时候就已经考虑到了,只是我们没注意到,还有些是边界的处理问题,加入这些让动规的过程变得很复杂,就没有加入进去,所以最好自己画图慢慢理解一下。
动规代码
public class problem32_2 {
public int longestValidParentheses(String s) {
int max = 0;
int dp[] = new int[s.length()];
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == ')') {
if (s.charAt(i - 1) == '(') {
dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
} else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
dp[i] = dp[i - 1] + ((i - dp[i - 1]) >= 2 ? dp[i - dp[i - 1] - 2] : 0) + 2;
}
}
max = Math.max(max, dp[i]);
}
return max;
}
public static void main(String[] args) {
problem32_2 pro=new problem32_2();
System.out.println(pro.longestValidParentheses("(()))"));
}
}