思路:
题目的主要信息:
- 一个序列中仅有"("、")"、"?"三种符号,将其中的"?"替换成任意括号,使之变成一个括号合法的序列
- 括号合法的序列定义:
- 空序列一定合法
- (+合法括号序列+) 为合法括号序列
- ()+合法括号序列为合法括号序列
通俗来说就是,一个左括号就一定有一个右括号匹配,同理一个右括号就一定有一个左括号匹配
- 如果能构造出来则返回恢复后任意合法的括号序列,否则返回Impossible
方法一:数组记录法
具体做法:
首先我们准备两个辅助数组,index记录问号"?"出现的下标,dp记录两个问号之间括号的差值,正数表示差相应右括号,负数表示差相应绝对值的左括号。
我们第一次对字符串进行遍历,将信息记录在两个辅助数组中。
然后,我们对每个问号"?"所在的位置进行判断,如果之前出现的左括号个数加上之前出现的问号数都小于右括号,则无法匹配成功,返回Impossible,否则我们可能匹配成功。
最后对问号进行替换,如果左括号多,即记录数大于0,则从右往左,先替换为右括号,再依次右括号、左括号得替换;如果右括号多即记录数小于0,则同理对称操作。
class Solution { public: string MissingBrackets(string brackets) { int n = brackets.length(); if(n % 2) //不为偶数一定不合法 return "Impossible"; vector<int> index;//index记录?出现的位置 vector<int> dp; //y记录两个?之间左右括号个数的差 int a = 0; //维护两个?之间左右括号个数的差 for(int i = 0; i < n; i++){//找到?的位置,即之间的括号差 if(brackets[i] == '?'){ index.push_back(i); //位置入数组 dp.push_back(a); a = 0; } else if(brackets[i] == ')') //遇到左加,遇到右减 a--; else a++; } index.push_back(n); dp.push_back(a); n = index.size(); a = 0; int q = 0; //记录问号出现次数 for(int i = 0; i < n; i++){ a += dp[i];//相差求和 if(-a > q++) //如果前面一直少,且少得还大于?出现的次数 return "Impossible"; } if(-a > index.size() - 1) //把所有?变为左括号都不能使左括号数量大于右括号 return "Impossible"; if(a > 0){ //左括号较多 a++; for(int i = n - 2; i >= 0; i--){ if(a > 0){ brackets[index[i]] = ')'; a--; } else{ brackets[index[i]] = '('; a++; } } } else{ //右括号较多 a--; for(int i = 0; i < n - 1; i++){ if(a < 0){ a++; brackets[index[i]] = '('; } else{ brackets[index[i]] = ')'; a--; } } } return brackets; } };
复杂度分析:
- 时间复杂度:,单独遍历两次
- 空间复杂度:,两个辅助数组长度都为
方法二:贪心
具体做法:
我们都直到合法的括号序列,左括号数与右括号数一定是各占一半。那么我们可以从括号数入手,每次都贪心地将差的左括号或者右括号补齐,最后再验证整个序列是否合法。
首先我们统计整个字符串中国左括号的数量,如果左括号数大于字符串长度的一半或者字符串长度不为偶数,我们可以断言这不可能组成合法序列。
再然后我们知道了左括号数是序列长度的一半,因此我们用得到还差多少左括号,然后我们遍历整个字符串,遇到一个问号我们查看是否还差左括号,如果差则将问号变成左括号,如果不差则将问号变成右括号。
最后我们遍历字符串检查是否合法。
class Solution { public: string MissingBrackets(string brackets) { int n = brackets.length(); int count = 0; for(int i = 0; i < n; i++) //统计左括号数 if(brackets[i] == '(') count++; if(n % 2 || count * 2 > n) //不为偶数一定不合法,左括号数大于一般肯定不合法 return "Impossible"; int rest = n / 2 - count; //还需要补充多少左括号 for(int i = 0; i < n; i++){ if(brackets[i] == '?' && rest != 0){ brackets[i] = '('; rest--; } else if(brackets[i] == '?') brackets[i] = ')'; } int all = 0; for(int i = 0; i < n; i++){ //检查修改后内容是否合法 if(brackets[i] == '(') all++; else if(brackets[i] == ')') all--; if(all < 0) return "Impossible"; } return brackets; } };
复杂度分析:
- 时间复杂度:,三次单独的遍历
- 空间复杂度:,无额外空间