leetcode题目 32. 最长有效括号

题目

给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。

示例

示例 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("(()))"));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值