Leetcode 32 Longest Valid Parentheses 解题报告。

Leetcode 32 Longest Valid Parentheses 解题报告。


题意

Given a string containing just the characters ‘(’ and ‘)’, find the length of the longest valid (well-formed) parentheses substring.
For “(()”, the longest valid parentheses substring is “()”, which has length = 2.

Another example is “)()())”, where the longest valid parentheses substring is “()()”, which has length = 4.

分析
要求是求出给定的括号字符串中最长的合法子序列。
首先我们判断一个括号序列是否合法的方法是使用栈的方法。
于是显然的可以将每个位置的字符作为起始符号,分多次运行这个判断是否合法的子程序,这样计算的时间复杂度为O(N^2)
对于字符串类型的问题可以尝试使用动态规划的方法,先尝试使用一维的动态规划
设字符串为S
取dp[i]表示从0到第i个位置得到的最长合法串,则dp[i+1]难以计算,由于只能利用前一个的信息,即S[i]和dp[i]
所以难以找到dp[i+1]的迭代计算方式。

考虑使用二维的动态规划,
dp[i, j],表示从字符串的第i个到第j个字符之间合法的字符串的最大长度。
可以得到 dp[i+1, j+1]的计算方式如下
|dp[i,j]+2, if S[i+1]==’(’ and S[j+1] == ‘)’
dp[i+1, j+1] = |
|dp[i,j], if S[i+1]==’(’ and S[j+1] != ‘)’ or S[i+1] == ‘(’
初始化d[0][0] = 1
答案为dp[0][n]
编码如下:
但是这样看似很好但是却无法实现,由于计算得到dp[i,j] 需要dp[i,j-1] dp[i+1,j], dp[i+1, j-1], 但是j>=i,
所以需要使用一个数字的斜上方和正上方和左边的值来得到一个值,这样的方式需要dp矩阵首先计算出第一行,这显然不行,所以变换思路

依然考虑使用一维dp的方法,但是需要改变dp数组的意义,令dp[i]表示以第i个符号作为结尾的一个合法字符串的最大长度(显然只有‘)’才能作为最后一个符号),只是这里需要每次记录一下dp的值取其中的最大值,本身dp[n]不代表答案。
于是有
ans = 0

if (s[i] == ‘)’) {
// 表示可以将上一个匹配的符号串包起来
// eg:
// dp[i-dp[i-1]-2] k k+1 k+dp[i-1] i
// )) (()) ()) ) ( ( ) ()()()()( ) )
// 可得dp[i] = dp[i - dp[i-1] - 1]+dp[i-dp[i-1]-2] + 2;
//
if (s[i-dp[i-1] -1] ==’(‘) {
dp[i] = dp[i - dp[i-1] - 1]+dp[i-dp[i-1]-2] + 2;
}
ans = max(ans, dp[i]);
}
最终答案为ans.


题目的思考:
本题开始就考虑直接用dp数组作为最终的子问题答案所以导致无法继续分析,然后开始考虑二维的dp但是遇到了不可求的情况,
这表明在同一个数组上进行二维的dp一般是不可行的这就需要变换思路,不要直接用dp作为答案,考虑每次更新答案,从子问题中挑选最优的一个作为答案,这样有可能在更低的维度解决问题。


AC代码

class Solution
{
  public:
    int longestValidParentheses(string s)
    {
        int ans = 0;
        s = ')'+s;
        vector<int> dp(s.length(), 0);
        for (int i = 2; i < s.length(); ++i) {
            if (s[i] == ')') {
                if (s[i-1] == '(') dp[i] = dp[i-2]+2;
                else if (dp[i-dp[i-1]-1] == '(') dp[i] = dp[i-1]+dp[i-dp[i-1]-2]+2;
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值