合法括号子段 51Nod - 1791 **

有一个括号序列,现在要计算一下它有多少非空子段是合法括号序列。

合法括号序列的定义是:

1.空序列是合法括号序列。

2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。



Input
多组测试数据。
第一行有一个整数T(1<=T<=1100000),表示测试数据的数量。
接下来T行,每一行都有一个括号序列,是一个由'('和')'组成的非空串。
所有输入的括号序列的总长度不超过1100000。
Output
输出T行,每一行对应一个测试数据的答案。
Sample Input
5
(
()
()()
(()
(())
Sample Output
0
1
3
1

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
typedef long long ll;
using namespace std;
/*
竟然会超时,memset都会超时,简直了
*/

char str[1100010];
ll dp[1100010];
int pos[1100010];

int main()
{
   int T;
   scanf("%d",&T);
   while(T--)
   {
       scanf("%s",str);
       stack<int> stk; 
       int len=strlen(str);
       for(int i=0;str[i];i++)//对括号进行一对一的匹配操作
       {
           dp[i]=0;
           pos[i]=-1;
           if(str[i]=='(')
           {
               stk.push(i);
               continue;
           }
           if(stk.empty())
                continue;
           int p=stk.top();
           pos[p]=i;//对()进行标记,p '(' , pos[p] ')',这样的话,我们就可以在后面计数的时候直接相加了。
          stk.pop();
       }
       dp[len]=0;
       ll ans=0;
       for(int i=len-1;i>=0;i--)//因为匹配的成不成功,我们只能在后面看到,一开始只有(,没有办法判断,
       {
           if(pos[i]==-1)
            continue;
           dp[i]=dp[pos[i]+1]+1;
                    //()()(),1 1 1,3 + 2 + 1,就像是
                    //                1
                    //           1   11
                    //       1  11  111
                    //    1 11 111 1111
                    //每次都是像这样不断出现新的,我们有规律可循
  ans+=dp[i]; } printf("%I64d\n",ans); } return 0;}


当然我们也可以从前面开始向后面加

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <cstring>
typedef long long ll;
using namespace std;
/*
竟然会超时,memset都会超时,简直了
*/

char str[1100010];
ll dp[1100010];
int pos[1100010];

int main()
{
   int T;
   scanf("%d",&T);
   while(T--)
   {
       scanf("%s",str);
       stack<int> stk;
       int len=strlen(str);
       for(int i=0;str[i];i++)
       {
           dp[i]=0;
           pos[i]=-1;
           if(str[i]=='(')
           {
               stk.push(i);
               continue;
           }
           if(stk.empty())
                continue;
           int p=stk.top();
           pos[i]=p;//记录( 的位置
           stk.pop();
       }
       dp[len]=0;
       ll ans=0;
       for(int i=0;i<len;i++)
       {
           if(pos[i]==-1)
            continue;
           if(pos[i]!=0)
             dp[i]=dp[pos[i]-1]+1;
           else
             dp[i]=1;
           ans+=dp[i];
       }
       printf("%I64d\n",ans);
   }
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值