非曰能,好学。欢迎大家一起交流学习

题目描述

链接:https://ac.nowcoder.com/acm/problem/21303

给你一个合法的括号序列s1,每次你可以删除一个"()"
你可以删除0个或者多个"()"
求能否删成另一个括号序列s2

问题分析

看答案,大家都用的动态规划,这里提供一个递归解法。
括号可以批成一组一组的,如下图所示,s1被分为两组,s2只包括一组。

怎么分组呢?对字符串中的左括号右括号计数,相等的时候,即为一组的结束位置。为了使得s1能0个或者多个"()"变成s2,需要s1中从前往后去pk s2中的组,若是能pk过,则去pk下一组,类似于判定一个字符串是否为另一个字符串的子序列

那怎么判断s1中的一组括号能pk过s2中一组括号呢?显然如上图所示s1的第一组是干不过s2中括号组,但是s1的第二组可以干过s2中括号组。总结规律可以得到:将预对比的两组括号,分别去掉开头和结尾,pk剩下的两括号字符串,而pk剩下的两括号字符串即原问题本身,从而完成递归。

代码实现

最后附上本人拙劣的代码,耗时6ms,内存消耗相比动态规划小很多

#include <bits/stdc++.h>
using namespace std;

class Solution 
{
    public:
        string s1;
        string s2;
        void read()
        {
            cin>>s1;
            cin>>s2;
        }

        int getNext(const string& S, int is)
        {
            int lcnt=0;
            int rcnt=0;
            while(is<S.size())
            {
                if(S[is]=='(')
                    lcnt++;
                else
                    rcnt++;
                if(rcnt==lcnt)
                    return is;
                is++;
            }
            return is;
        }

        // 多组原子对多组原子
        bool isMatch(int l1, int r1, int l2, int r2)
        {
            int i1,i2,j1,j2;
            j1=l1-1;
            i2=l2;
            j2=getNext(s2,i2);

            while(j2<=r2)
            {
                while(1)
                {
                    i1=j1+1;;
                    if(i1>r1)
                        return false;
                    j1=getNext(s1,i1);
                    if( isCover(i1,j1,i2,j2) )
                    {
                        i2=j2+1;
                        if(i2>r2)
                            return true;
                        j2=getNext(s2,i2);
                        break;
                    }
                }
            }
            return true;
        }

        //s1的从l1到r1,能cover住s2的l2到r2吗, l1-l1是个原子,即(xxx)
        bool isCover(int l1, int r1, int l2, int r2)
        {
            if(r1-l1<r2-l2)
                return false;
            if(l2+1==r2)
                return true;
            return isMatch(l1+1,r1-1, l2+1,r2-1);

        }
        void process()
        {
            read();
            if(isMatch(0,s1.size()-1, 0, s2.size()-1))
                cout<<"Possible"<<endl;
            else
                cout<<"Impossible"<<endl;
            return ;
        }
};

int main()
{
    Solution s;
    s.process();
    return 0;
}