算法算法提高之LeetCode刷题数据结构和算法分析

32-最长有效括号-挺复杂的DP问题

2020-04-14  本文已影响0人  华雨欣

写在前面

递推公式难分析的DP问题是真的挺难的,想了好久也没有想出来怎么做(除了暴力。。。),还是很需要练习啊。

题目

核心思路

LeetCode的20. 有效的括号相对来说就很简单,因为只用遍历一次看括号是否有效,不过这道题要求出最长的有效括号,涉及到字符串的子串,就变得很难了,因为可能性真的很多。
首先,暴力法就不多说了,遍历每一种可能的子串,然后对每个子串判断是否是有效的即可。时间复杂度O(n³),提交会在227个用例超时。
然后就是重头戏动态规划了。既然用动态规划,那该有的步骤当然不能少。

子问题

既然要求的是有效括号,那么最小的有效括号很容易可以想到 : (),如果想保证括号仍然是有效的,那么可以在这个最小的基础上后边加若干对括号,或者外边套若干层括号,即 ()()()((()))。对任意有效括号子串,都可以有这两种扩展的方式,这也就算是找到了子问题。

定义DP数组

有了子问题,就要定义dp数组了,也就是局部的最优解,由于最后要求的是最长的有效括号,同时,为了不漏掉所有情况,那么 dp[i] 就可以表示以i下标位置结尾的最长有效括号。并且要保留全局最优解,所以每计算一次dp[i]就要比较留下最大值。

状态转移公式

虽然前边可能很顺利能想到,但是这道题的状态转移公式是真的难想。
根据前边DP数组的定义,dp[i]会面对两种情况:
(1)s.chatAt(i) == '(' (2)s.charAt(i) == ')'

  1. 首先来讨论第一种情况,字符串以'('结尾,显然该字符串不可能是有效的,所以在这时 dp[i] = 0;
  2. 然后来看第二种情况,对于以')'结尾的字符串,他有三种情况:
    (1)i == 0 即字符串的第一个字符是')'(2)s.charAt(i - 1) == '('(3)s.charAt(i - 1) == ')'

动态规划代码

class Solution {
    public int longestValidParentheses(String s) {
        int maxLen = 0;
        int[] dp = new int[s.length() + 1];
        for (int i = 2; i < dp.length; i++) {
            if (s.charAt(i - 1) == '(') {
                continue;
            }
            if (s.charAt(i - 2) == '(') {
                dp[i] = dp[i - 2] + 2;
            } else {
                dp[i] = (i - 2 - dp[i - 1] >= 0) && s.charAt(i - 1 - dp[i - 1] - 1) == '(' ? dp[i - 1] + 2 + dp[i - 2 - dp[i - 1]] : 0;
            }
            maxLen = Math.max(maxLen, dp[i]);
        }
        return maxLen;
    }
}

总结

这道题的递推公式真的难想到,而且还要注意很多细节,真的是很难的一道DP题了,另外官方题解还有两种方法,一种是用栈,要注意保留每个有效括号串最开始位置的下标;还有一种使用双指针,注意不满足条件时将left和right的值归零即可。本人还是菜鸡一枚正在努力学习,有错误或者写的不合适的地方还请指出,感恩相遇~

上一篇下一篇

猜你喜欢

热点阅读