[序]最长有效括号的长度-动态规划--英雄会

本文探讨如何解决寻找字符串中最长有效括号子串的问题,通过动态规划的方法,采用倒序匹配策略,避免了由于非连续有效括号导致的错误。通过实例解释了算法思路,并给出了代码实现,最后邀请读者进行交流讨论。

给定只包含括号字符'('和 ')''的字符串,请找出最长的有效括号内子括号的长度。举几个例子如下: 例如对于"( ()",最长的有效的括号中的子字符串是"()" ,有效双括号数1个,故它的长度为 2。  再比如对于字符串") () () )",其中最长的有效的括号中的子字符串是"() ()",有效双括号数2个,故它的长度为4。  再比如对于"( () () )",它的长度为6。     

前一篇已经说了,直接匹配后虽然个人认为正确,但是交上去有误,虽然没有给出测试点,但是感觉应该是“有效括号”名词理解的问题,相信有很多小伙伴和我是同样的。根据小伙伴的提醒,确实需要连续。

如对字符串"()(()"的处理,按照最长括号的理解,有效括号是4个

但是,中间第三个"("却隔开了两个有效括号,真实答案为2个

事实证明,确实得按照连续考虑...(这一题只能交一次,所以开了个小号在英雄会上重新交了一次,问题解决)

 

动态规划:

下面说一下思想,既然已经了解题意是需要连续的有效括号的话,就不能按照之前那样伪入栈出栈来解决了,早上结合别人的帮助,自己解决了这个:

采用的是倒序匹配的方法,if(s[i] == '('),则继续进行匹配')',否则i--;继续向前匹配;

若继续匹配,通过int j = i + 1 + dp[i + 1];  可以避免多余匹配,将之前有匹配的直接加上,然后匹配')';

匹配成功之后,修改dp[i]的值(这才是动态规划的实质);

再将 dp[i] += dp[j]; 即可得到最长有效,其中d[j]的值是我们有i匹配至j-1时,如果j也和前面连续的话,就可以进行有效叠加;

//核心代码:

for(int i = n - 2; i >= 0; i--)  //倒序操作
    {
        if(s[i] == '(')
        {
            int j = i + 1 + dp[i + 1];  //避免多余匹配

            if(s[j] == ')' && j < n)
            {
                dp[i] = dp[i + 1] + 2;  //匹配,并改变此时的点到尾端的最长有效
                if (j + 1 < n)
                {
                    dp[i] += dp[j + 1];  //此时若是连续即可加上之前匹配,否则+0,即非连续
                }

            }
        }
    }

 


接下来直接找到dp中最大值即可,即是最长有效(因为dp[i] = dp[i + 1] + 2;故不用乘二)

下面贴出代码(加了很多输出是便于理解,大家可以试试):

#include <iostream>
#include <cstring>

using namespace std;

int longestValidParentheses(string s)
{
    //动态规划
    int sum = 0;  //最长有效
    int n = s.length();

    int *dp = new int[n];

    for(int i = 0; i < n; i++)  //作为记录对应与s[i]的最长有效值
       dp[i] = 0;

    for(int i = n - 2; i >= 0; i--)  //倒序操作
    {
        if(s[i] == '(')
        {
            int j = i + 1 + dp[i + 1];  //避免多余匹配

            if(s[j] == ')' && j < n)
            {
                dp[i] = dp[i + 1] + 2;  //匹配,并改变此时的点到尾端的最长有效
                if (j + 1 < n)
                {
                    dp[i] += dp[j + 1];  //此时若是连续即可加上之前匹配,否则+0,即非连续
                }

            }
        }
    }

    for(int i = 0; i < n; i++)  //找到最大值
    {
        cout<<dp[i]<<"  ";  //输出各个点的最长有效,顺序...
        if(sum < dp[i])
            sum = dp[i];
    }
    cout<<endl;
    delete []dp;
    return sum;
}

int main()
{
    char s[] = "()(()";
    int sum = longestValidParentheses (s);

    for(int i = 0; s[i] != '\0'; i++)  //找到最大值
    {
        cout<<s[i]<<"  ";  //输出各个点的最长有效,顺序...
    }
    cout<<endl;
    cout<<"最长有效长度"<<sum<<endl;
    return 0;
}

 

测试点:

 

如果有考虑不周到的,各位大牛提点一下,3Q...多多交流

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值