CF Round 138C Bracket Sequence 括號匹配,DP

题意:长度为n的括号序列,包括'[]','()'.要求找到一个正确的括号区间[L,R]并且'['的数量最多.
n<=1e5.输出最多'['的值和区间[L,R].


因为'['为左端点时,下一个数只能为']'或者左括号.设dp[i]为左端点为i时最远能完成匹配的位置.
若s[i]==']'||s[i]==')] dp[i]=-1;
若s[i]=='[' 当s[i+1]==']' dp[i]=max(i+2,dp[i+2]) ,当s[i+1]=='[||('  p=dp[i+1]+1并且s[p]==']' dp[i]=max(p,dp[p+1])

枚举左端点i,右端点R=dp[i].预处理'['的前缀和即可.

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
char s[N];
int L,R=-1,res=0,dp[N],pr[N];
int main()
{
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n;i++)
	{
		pr[i]=pr[i-1];
		if(s[i]=='[')
			pr[i]++; 
	}
	for(int i=n;i>=1;i--)
	{
		if(s[i]==')'||s[i]==']')
		{
			dp[i]=i-1;
			continue;
		}
		if(s[i]=='('&&s[i+1]==']' || s[i]=='['&&s[i+1]==')')
			continue;
		if(s[i]=='[')
		{
			if(s[i+1]==']')
				dp[i]=max(i+1,dp[i+2]);
			else
			{
				int p=dp[i+1]+1;
				if(s[p]==']')
					dp[i]=max(p,dp[p+1]);
				else
					dp[i]=i-1;
			}
		}
		if(s[i]=='(')
		{
			if(s[i+1]==')')
				dp[i]=max(i+1,dp[i+2]);
			else
			{
				int p=dp[i+1]+1;
				if(s[p]==')')
					dp[i]=max(p,dp[p+1]);
				else
					dp[i]=i-1;
			}
		}
	//	cout<<i<<' '<<dp[i]<<'\n';	
	}
	for(int i=1;i<=n;i++)
	{
		int l=i,r=dp[i],cnt=pr[r]-pr[l-1];
		if(cnt>res)
		{
			res=cnt;
			L=l,R=r;
		}
	}
	printf("%d\n",res);
	for(int i=L;i<=R;i++)
		printf("%c",s[i]);
	printf("\n");
	return 0;
}

標程解法:用棧維護左括號的二元組(s[i],i) 為每個右括號匹配其位置.

模擬時 若棧頂和s[i]不匹配. 出現非法對,則清空棧. 

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl "\n"
#define int long long
const int N=1e5+5;
int n;
int pref[N], leftidx[N], bestend[N];
string s;
map<char, char> opp;
stack<pair<char, int> > st;

int range(int l, int r)
{
	if(l>=1)
		return pref[r] - pref[l-1];
	return pref[r];
}

int32_t main()
{
	IOS;
	cin>>s;
	n=s.size();
	for(int i=0;i<n;i++)
	{
		if(i>=1)
			pref[i]=pref[i-1] + (s[i]=='[');
		else
			pref[i]=(s[i]=='[');
	}
	int ans=0, idx=0, len=0;
	opp[')']='(';
	opp[']']='[';
	for(int i=0;i<n;i++)
	{
		if(s[i]=='('||s[i]=='[')
		{
			st.push({s[i], i});
		}
		else
		{
			if(!st.size())
				continue;
			if(st.top().first!=opp[s[i]])
			{
				while(st.size())
					st.pop();
			}
			else
			{
				pair<char, int> p=st.top();
				st.pop();
				int store=0;
				if(p.second>=1)
					store=bestend[p.second-1];
				if(store + range(p.second, i)>ans)
				{
					ans=store + range(p.second, i);
					idx=p.second;
					if(store>0)
						idx=leftidx[p.second-1];
					len=i-idx+1;
				}
				bestend[i]=store + range(p.second, i);
				leftidx[i]=p.second;
				if(store>0)
						leftidx[i]=leftidx[p.second-1];
			}
		}
	}
	cout<<ans<<endl;
	cout<<s.substr(idx, len);
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值