P1944 最长括号匹配
题意
最长括号匹配
题目描述
对一个由(,),[,]括号组成的字符串,求出其中最长的括号匹配子串。具体来说,满足如下条件的字符串成为括号匹配的字符串:
1.(),[]是括号匹配的字符串。
2.若A是括号匹配的串,则(A),[A]是括号匹配的字符串。
3.若A,B是括号匹配的字符串,则AB也是括号匹配的字符串。
例如:(),[],([]),()()都是括号匹配的字符串,而][,[(])则不是。
字符串A的子串是指由A中连续若干个字符组成的字符串。
例如,A,B,C,ABC,CAB,ABCABCd都是ABCABC的子串。空串是任何字符串的子串。
输入格式
输入一行,为一个仅由()[]组成的非空字符串。
输出格式
输出也仅有一行,为最长的括号匹配子串。若有相同长度的子串,输出位置靠前的子串。
样例 #1
样例输入 #1
([(][()]]()
样例输出 #1
[()]
样例 #2
样例输入 #2
())[]
样例输出 #2
()
提示
【数据范围】
对20%的数据,字符串长度<=100.
对50%的数据,字符串长度<=10000.
对100%的数据,字符串长度<=1000000.
tags
线性dp
思路
解法1
- 类最长上升子序列
- dp[i]表示:以第i个元素结尾的最长括号匹配
- 状态转移:
- 若s[i]为[或(则dp[i]=0
- dp[i]可以从dp[i-1]转移过来,即从以s[i-1]为结尾的最长括号匹配。若s[i-1-dp[i-1]]==s[i],则dp[i]=dp[i-1]+2
- 若不满足,那么s[i]就不能加到前面去了,则dp[i]=0
- 但是注意题目中第三个条件:“若A,B是括号匹配的字符串,则AB也是括号匹配的字符串。”,我们还需去加上以s[i-2-d[i-1]]为结尾的最长括号匹配
AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+10;
int dp[maxn];
int main(){
string s;
cin>>s;
int len=s.length();
s='*'+s;
int ans=0,l=0,r=0;
for(int i=2;i<=len;i++){
if(s[i]=='['||s[i]=='(')continue;
if((s[i]==']'&&s[i-1-dp[i-1]]=='[')||(s[i]==')'&&s[i-1-dp[i-1]]=='(')){
dp[i]=dp[i-1]+2+dp[i-2-dp[i-1]];
if(ans<dp[i]){
ans=dp[i];
l=i-dp[i]+1;
r=i;
}
}
}
for(int i=l;i<=r;i++)cout<<s[i];
cout<<endl;
return 0;
}
解法2
- 括号匹配:如果一个括号串中’(‘与’)'能相互抵消(要临近!),那么这两括号相互匹配
- ())中只有s[0]与s[1]能够相互抵消
- (()())(中s[1]与s[2]抵消,s[3]与s[4]抵消,当他们抵消完之后s[0]与s[5]可以相互抵消
- 我们就可以设置一个栈,将元素逐个入栈,若出现栈顶元素与s[i]想匹配,则出栈(以实现抵消操作让其他匹配的括号临近)
- 我们所求的最长括号匹配就是在出栈的时候被更新
- 注意如果出栈后栈为空,那么说明从0到i都是括号匹配,要单独考虑
AC代码
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
stack<int>st;
int ans=0,l,r;
for(int i=0;i<s.length();i++){
if(s[i]=='('||s[i]=='[')st.push(i);//如果为(或[肯定直接入栈
else if(st.empty()||s[st.top()]==')'||s[st.top()]==']'||(s[st.top()]=='('&&s[i]==']')||(s[st.top()]=='['&&s[i]==')'))st.push(i);//如果栈为空或者没有括号匹配,则入栈
else{//如果非空且有括号匹配,则更新状态
st.pop();//先出栈
if(st.empty()){//栈空时,此时有括号匹配从0到i,看是否可以去更新
if(ans<i+1)ans=i+1,l=0,r=i;
}
else {
if(ans<i-st.top())ans=i-st.top(),l=st.top()+1,r=i;//栈非空时,有括号匹配从st.top()+1到i,看是否可以更新
}
}
}
for(int i=l;i<=r;i++)cout<<s[i];
}