P10472 括号画家

· · 题解

思路

这题要用栈来做。

这道题我们可以先考虑从简单的入手:如何判断一个括号序列是否合法。

这个可以如果是左括号加入栈内。 如果是右括号的话就看一下栈顶元素是否和它匹配。 如果不匹配就不是一个合法的括号序列。

然后到这道题上就稍微转化一下。

你需要对于每个右括号找到与之相匹配的左括号。 然后对这个取个 max 就可以。 如果匹配不上需要将栈清空。

代码时间~~~

好,我们写完了这个就可以自己尝试写一下这道题的代码了。

40 分 code

#include<algorithm>  //含sort函数等
#include<cmath>      //关于数学函数的头文件
#include<cstring>    //string字符串头文件
#include<cstdio>     //C语言的头文件
#include<iomanip>    //用于cout<<fixed<<setprecision()
#include<iostream>   //含cin,cout
#include<queue>      //普通队列(只能一边进一边出)(先进先出)
#include<deque>      //双向队列(两边都可以进出)(先进先出)
#include<stack>      //栈(先进后出,后进先出)
#include<list>       //列表
#include<vector>     //动态数组
#include<map>        //关联式容器
#include<set>        //集合
#include<climits>    //INT_MAX与INT_MIN
using namespace std;
string s;
stack<int>stk;
int len;
int sum,ans=0;
int main()
{
    cin>>s;
    len=s.size();
    for(int i=0;i<len;i++){
        if(s[i]=='('||s[i]=='['||s[i]=='{'){
            stk.push(i);
            continue;
        }
        if(!stk.empty()){
            if(((s[i]==')'&&s[stk.top()]=='(')||(s[i]==']'&&s[stk.top()]=='[')||(s[i]=='}'&&s[stk.top()]=='{'))){
                ans=max(ans,i-stk.top()+1);
                stk.pop();
            }else{
                while(!stk.empty()){
                    stk.pop();
                }
            }
        }
    }
    cout<<ans<<endl;
    return 0;  //每日一个好习惯,老师远离我
}

结果。

为什么是四十分呢?

显然,我们的代码在遇到 ()()() 的时候会出问题,正确答案显然是 6 ,但我们输出的是 2 。

怎么改呢?

我们可以记录一下当前这个序列的开始点,也就是括号序列的最左合法的括号点是多少。

72 分 code

#include<algorithm>  //含sort函数等
#include<cmath>      //关于数学函数的头文件
#include<cstring>    //string字符串头文件
#include<cstdio>     //C语言的头文件
#include<iomanip>    //用于cout<<fixed<<setprecision()
#include<iostream>   //含cin,cout
#include<queue>      //普通队列(只能一边进一边出)(先进先出)
#include<deque>      //双向队列(两边都可以进出)(先进先出)
#include<stack>      //栈(先进后出,后进先出)
#include<list>       //列表
#include<vector>     //动态数组
#include<map>        //关联式容器
#include<set>        //集合
#include<climits>    //INT_MAX与INT_MIN
using namespace std;
string s;
stack<int>stk;
int len;
int sum,ans,l=-1;
int main()
{
    cin>>s;
    len=s.size();
    for(int i=0;i<len;i++){
        if(s[i]=='('||s[i]=='['||s[i]=='{'){
            if(l==-1){
                l=i;
            }
            stk.push(i);
            continue;
        }
        if(!stk.empty()){
            if(((s[i]==')'&&s[stk.top()]=='(')||(s[i]==']'&&s[stk.top()]=='[')||(s[i]=='}'&&s[stk.top()]=='{'))){
                ans=max(ans,i-stk.top()+1);
                if(stk.size()==1){
                    ans=max(ans,i-l+1);
                }
                stk.pop();
            }else{
                while(!stk.empty()){
                    stk.pop();
                }
                l=-1;
            }
        }else{
            l=-1;
        }
    }
    cout<<ans<<endl;
    return 0;  //每日一个好习惯,老师远离我
}

结果。

Why?

我们很容易看出,但我们的代码遇到 [()()} 时有问题。

怎么办?

如果说当前已经可以匹配了,并且不剩左括号了,就记录一下当前左括号位置就行了。

AC code

#include<algorithm>  //含sort函数等
#include<cmath>      //关于数学函数的头文件
#include<cstring>    //string字符串头文件
#include<cstdio>     //C语言的头文件
#include<iomanip>    //用于cout<<fixed<<setprecision()
#include<iostream>   //含cin,cout
#include<queue>      //普通队列(只能一边进一边出)(先进先出)
#include<deque>      //双向队列(两边都可以进出)(先进先出)
#include<stack>      //栈(先进后出,后进先出)
#include<list>       //列表
#include<vector>     //动态数组
#include<map>        //关联式容器
#include<set>        //集合
#include<climits>    //INT_MAX与INT_MIN
using namespace std;
const int MAX=10000+5;
string s;
stack<int>stk;
int len;
int f[MAX];
int sum,ans,l=-1;
int main()
{
    cin>>s;
    len=s.size();
    memset(f,127/3,sizeof(f));
    for(int i=0;i<len;i++){
        if(s[i]=='('||s[i]=='['||s[i]=='{'){
            if(l==-1){
                l=i;
            }
            stk.push(i);
            continue;
        }
        if(!stk.empty()){
            if(((s[i]==')'&&s[stk.top()]=='(')||(s[i]==']'&&s[stk.top()]=='[')||(s[i]=='}'&&s[stk.top()]=='{'))){
                f[i]=min(stk.top(),f[stk.top()-1]);
                ans=max(ans,i-f[i]+1);
                stk.pop();
            }else{
                while(!stk.empty()){
                    stk.pop();
                }
                l=-1;
            }
        }else{
            l=-1;
        }
    }
    cout<<ans<<endl;
    return 0;  //每日一个好习惯,老师远离我
}

就是这样维护一个 f 数组记录一下当前可以匹配的左端点是多少。