【面试题-刷题记录】力扣第32题,最长有效括号,难度:困难

力扣 32. 最长有效括号(困难)

这个题目我最开始想到的是栈,遍历字符串的过程中,需要记录每一个合法子串的长度,这也是难点所在,因为在遍历过程中不方便记录每一个合法子串的长度,因此这里需要记录一个“最后一个没有被匹配的右括号的下标”,初始栈时为了记录“最后一个没有被匹配的右括号的下标”,会将-1入栈。
遍历过程中一共有两种情况:

  1. 匹配到左括号‘(’,此时入栈即可。
  2. 匹配到右括号’)',此时先出栈,出栈后判断栈是否为空:
    • 如果为空,表面该右括号是没有被匹配的,因为栈中必须要保证有一个“最后一个没有被匹配的右括号的下标”,因此该右括号的下标入栈。
    • 如果不为空,则表明匹配成功,那么此时该右括号的位置减去栈顶元素的位置即可得到子串长度。

遍历过程中记录最大的长度则为最终结果。

代码
class Solution {
	public int longestValidParentheses(String s) {
		if (s.length() == 0) return 0;
        int res = 0;
        Stack<Integer> st = new Stack<>();
        st.push(-1);
        for (int i = start; i <= end; i++) {
            if (s.charAt(i) == '(') {
                st.push(i);
            } else {
                st.pop();
                if (!st.isEmpty()) {
                    res = Math.max(res, i - st.peek());
                } else {
                    st.push(i);
                }
            }
        }
        return res;
	}
}

动态规划

按照卡尔哥的动规五部曲来做:

  1. 定义数组int[] dp = new int[s.length() - 1];表示从0到i的范围内最长的有效括号长度为dp[i]
  2. 定义状态转移方程。这里分情况讨论:
    • 如果当前第i个元素为')',则看i - 1元素:
      • 如果i - 1'(',如果i == 1dp[i]直接赋值为2。
      • 否则,dp[i] = dp[i - 2] + 2,因为此时这一对括号已经配对好了,那么就需要根据这对括号前一位的值来更新。
    • 如果当前第i个元素为'(',则表明此时可能有嵌套的情况,例如()(())这种,当i = 5时,首先根据i - 1获得内部括号的个数,即dp[i - 1,再判断i - dp[i - 1] - 1位置是否为'(',如果是,则表明外层括号也匹配成功,dp[i] = dp[i - 1] + 2,由于题目求的时最长有效括号,因此还要判断最外层的前一个元素是否也是匹配成功的,如果是则加上去,但是此时有可能会越界(例如(())(),此时嵌套发生在下标为3的位置,i - dp[i] = -1),因此要做个判断:if (i - dp[i] >= 0),成立则dp[i] += dp[i - dp[i]]
代码
class Solution {
    public int longestValidParentheses(String s) {
        int res = 0;
        // 定义dp[i]表示第i个字符时最长有效括号字串长度为dp[i]
        // 初始化,全部默认为0
        int[] dp = new int[s.length()];
        // 定义count对)计数
        int count = 0;
        // 遍历顺序,从下标为1的开始
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    // 如果是第一对括号
                    if (i == 1) {
                        dp[i] = 2;
                    } else {
                        dp[i] = dp[i - 2] + 2;
                    }
                } else {
                	// 计算出左括号的位置,判断是否越界
                    if (i - dp[i - 1] - 1 >= 0) {   
                    	// 判断是否为左括号
                        if (s.charAt(i - dp[i - 1] - 1) == '(') {
                        	// 如果是,则直接加2
                            dp[i] = dp[i - 1] + 2;
                            // 如果与前面的连续,此时也要加上前面的值
                            if (i - dp[i] >= 0)
                                dp[i] += dp[i - dp[i]];
                        }
                    }
                }
            }
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

这是按照我个人的理解来写的,如果感觉不太明白可以去力扣看官方题解。

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值