bit程序设计 括号序列 栈+前缀和

题目描述:

一个括号序列是指一个由'(', ')', '[', ']'四种字符组成的字符串。

一个只包含数字,加号'+',和上述四种括号的合法算数表达式,去掉数字和加号之后得到的括号序列成为合法的括号序列。我们定义空串也是合法的括号序列。

例如(1) + [2], ([3]), 4 + [5]相应的括号序列 "()[]", "([])", "[]"都是合法的括号序列。而(6 + 7], [8 + ((9对应的"(]", "[(("则是非法的。

字符串 s0s1s2s|s|1 的子串 s[l,r](0 lr<|s|) 是指 slsl+1sr

现在给定一个括号序列,请找出其中的一个子串,使得这个子串是合法的括号序列,且包含的'['数量最多。


输入:

一个括号序列s。 1|s|5×105

输出:

第一行,答案要求的子串中包含'['的数量。

如果答案是0,输出到此为止,否则:

第二行,两个整数l, r。表示子串第一个字符的位置和最后一个字符的位置。

如果有多个满足条件的字符串,请输出使得子串长度最大的答案。如果长度最大的仍有多个,请输出r最大的。

思路:

首先说一下大思路:

处理出从字符串s每一个位置i开始的最长的合法串,用ans[i]记录,其中ans[i].l== i,ans[i].r 为从i开始最长合法串的最右端,ans[i].cnt = r - l + 1;

用数组num[x]表示前x个元素中 ‘[’ 出现的次数,这个可以直接循环一遍得到;

则对于每个位置i,num[ans[i].r] - num[ans[i].l - 1]表示从i开始的最长合法串中的'['的个数;

那么关键是怎么得到ans数组?

处理括号问题,常用栈,我们用数组a模拟一个栈,用cur来表示栈顶指针,栈中存储结构体node1,a[cur].ch表示栈顶的字符,a[cur].pos表示栈顶字符是字符串s中的第pos个元素,如果栈顶是'('且新加入')',那么弹出栈顶元素(栈顶为'['时类似),第i次循环加入s[i]之后,栈顶元素在s中位置p是a[cur].pos,那么如果i - p大于0就把ans[p+1].r置为i,ans[p+1].cnt置为i - p,如此就可以O(n)维护ans


AC代码(注意别被查重!!!):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 500005
int Max(const int a , const int b)
{
    return a < b ? a : b ;
}
char s[maxn] ;
int num[maxn];
struct node1
{
    char ch ;
    int pos ;
}a[maxn];
struct node2
{
    int cnt , l , r ;
}ans[maxn];
int main()
{
    scanf("%s" , s + 1 ) ;
    int len = strlen( s + 1 ) , cur = 0 , i ;
    num[0] = 0;
    for(i = 1 ; i<= len ; i++){
        num[i] = num[i - 1] + (s[i] == '[') ;
    }
    for( i = 1 ; i<= len ; i++){
        ans[i].cnt = 0;
        ans[i].l = i ;
    }
    for( i = 1 ; i <= len ; i++){
        struct node1 st1 = {s[i] , i};
        if((a[cur].ch=='(' &&st1.ch ==')')||(a[cur].ch=='[' &&st1.ch ==']')){
            --cur ;
        }
        else{
            a[++cur] = st1 ;
        }
        int x = a[cur].pos ;
        if(ans[x+1].cnt < i - x){
            ans[x+1].cnt = i - x ;
            ans[x+1].r = i;
        }
    }
    int res = 0 , ansl , ansr ;
    for(i = len ; i > 0 ; i--){
        if(ans[i].cnt){
            int comp =  num[ans[i].r] - num[ans[i].l - 1] ;
            if(comp > res){
                res = comp;
                ansl = ans[i].l;
                ansr = ans[i].r;
            }
            else if(comp == res){
                if(ans[i].r - ans[i].l > ansr - ansl){
                    ansl = ans[i].l;
                    ansr = ans[i].r;
                }
            }
        }
    }
    printf("%d\n",res);
    if(res){
        printf("%d %d\n",ansl-1,ansr-1);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值