栈之合法括号字符串(RBS)
参考资料来源灵神在力扣所发的题单,仅供分享学习笔记和记录,无商业用途。
核心思路:查看栈的基础篇-CSDN博客,部分题目可以不用栈,而是用一个数字记录嵌套深度。
应用场景:处理具有完全包含关系(括号关系)的问题,最近元素匹配问题。递归实现和栈实现本质上没有区别
力扣刷题
921. 使括号有效的最少添加
题意:给定只有"("")"字符组成的字符串,最小化操作次数让括号合理化
思路:
遇到左括号进行次数记录,碰到右括号且没有左括号需要进行补充左括号++
否则次数--。操作数等于左括号数+补充左括号操作数量
class Solution {
public:int minAddToMakeValid(string s) {//题意:给定只有"("")"字符组成的字符串,最小化操作次数让括号合理化//思路:遇到左括号进行次数记录,碰到右括号且没有左括号需要进行补充左括号++,//否则次数--。操作数等于左括号数+补充左括号操作数量int ret=0,p=0;for(auto x:s){if(x=='(') p++;else if(p) p--;else ret++;}return p+ret; }
};
856. 括号的分数
规则:
当字符串或者子串为最小平衡单元()时,这段的得分为 1 分。
一个平衡括号字符串可拆分为两个独立的平衡括号字符串A和B(A、B 无嵌套,仅左右并列)进行分数累加
若一个平衡括号字符串的整体是 “一个平衡括号字符串 A 被一对外层括号包裹”(即整体结构为 (A)),则整个字符串的得分为 2 * A 的得分(即 “嵌套结构翻倍”)。
思路:
规则一和规则三可以用1<<深度-1表示,因括号字符串是合理的,可以将遇到‘)’时候如果前一位是'('才进行累加计算,可以保证嵌套括号子串只计算一次结果且满足规则二。
class Solution {
public:int scoreOfParentheses(string s) {//规则:当字符串或者子串为最小平衡单元()时,这段的得分为 1 分。//一个平衡括号字符串可拆分为两个独立的平衡括号字符串A和B(A、B 无嵌套,仅左右并列)进行分数累加//若一个平衡括号字符串的整体是 “一个平衡括号字符串 A 被一对外层括号包裹”(即整体结构为 (A)),则整个字符串的得分为 2 * A 的得分(即 “嵌套结构翻倍”)。//思路:规则一和规则三可以用1<<深度-1表示,因括号字符串是合理的,可以将遇到‘)’时候如果前一位是'('才进行累加计算,可以保证嵌套括号子串只计算一次结果且满足规则二。int buff=0,ret=0;for(int i=0;i<s.size();i++){if(s[i]=='(') buff++;else{buff--;if(s[i-1]=='(') ret+=1<<buff;}}return ret;}
};
1249. 移除无效的括号
题意:
给定一个带括号和其他字符的字符串,要求让括号保证合理性将错误括号移除。返回有效「括号字符串」
思路:
可能出现左括号、右括号、左右括号都冗余的情况。如果在遍历中出现左括号没有右括号出现放入删除哈希表,遍历结束后还有栈中还有左括号说明冗余也要加入删除哈希表中。最后根据哈希表进行重构字符串即可
class Solution {
public:string minRemoveToMakeValid(string s) {//题意:给定一个带括号和其他字符的字符串,要求让括号保证合理性将错误括号移除。返回有效「括号字符串」//思路:可能出现左括号、右括号、左右括号都冗余的情况。如果在遍历中出现左括号没有右括号出现放入删除哈希表,遍历结束后还有栈中还有左括号说明冗余也要加入删除哈希表中。最后根据哈希表进行重构字符串即可string ret="";stack<int> ans;set<int> m;for(int i=0;i<s.size();i++){if(s[i]=='(') ans.push(i);else{if(s[i]==')'){if(!ans.empty()) ans.pop();else m.insert(i);}}}while(!ans.empty()){m.insert(ans.top());ans.pop();}for(int i=0;i<s.size();i++){if(m.find(i)!=m.end()) continue;ret+=s[i];}return ret;}
};
1963. 使字符串平衡的最小交换次数
题意:
给定一组只有‘[]’组成的字符串,左括号的数量一定等于右括号,求最小交换次数使字符串变成括号合理字符串
思路:
统计右括号位置不合法的数量,依题意得出不合法括号对的数量,每次交换最多能解决2组
贪心策略:不合法括号对的数量/2向上取整得出最小交换次数,向上取整解决奇数组括号对的情况
为什么每次最多能解决2组?
举例:]][[ ]]][[[:多组括号对总会存在一种方法交换能解决2组。
class Solution {
public:int minSwaps(string s) {//题意:给定一组只有‘[]’组成的字符串,左括号的数量一定等于右括号,求最小交换次数使字符串变成括号合理字符串//思路:统计右括号位置不合法的数量,依题意得出不合法括号对的数量,每次交换最多能解决2组//贪心策略:不合法括号对的数量/2向上取整得出最小交换次数,向上取整解决奇数组括号对的情况//为什么每次最多能解决2组?//举例:]][[ ]]][[[:多组括号对总会存在一种方法交换能解决2组。 int buff=0,ret=0;for(auto x:s){if(x=='[') buff++;else if(buff) buff--;else ret++;}return ceil(ret/2.0);}
};
678. 有效的括号字符串
题意:
给定一组只包含()*的字符串。'*'可以被视为单个右括号')'或单个左括号'('或一个空字符串 ""。求是否存在某种策略能变成平衡括号字符串。
思路:
用两个栈记录左括号和*的出现位置,遇到右括号先用左括号栈,次之用*栈,最后都没有则说明字符串一定不能平衡
在消除右括号后,在处理左括号和*。这两个栈都是升序的,要保证左括号栈值要小于*号栈值才能合法。所以栈顶匹配栈顶最可能合法
*栈可以不用在意,因为它可以变成空字符,当上述处理后,根据左括号栈就能判断是否能成功了
贪心策略:遇到右括号优先用左括号进行配对,因为*可以变成空字符不会影响到结果。
反证法:优先使用*栈,那么(*)是错误的,正确结果是true,从而证明不能优先*栈
class Solution {
public:bool checkValidString(string s) {//题意:给定一组只包含()*的字符串。'*'可以被视为单个右括号')'或单个左括号'('或一个空字符串 ""。求是否存在某种策略能变成平衡括号字符串。//思路:用两个栈记录左括号和*的出现位置,遇到右括号先用左括号栈,次之用*栈,最后都没有则说明字符串一定不能平衡//在消除右括号后,在处理左括号和*。这两个栈都是升序的,要保证左括号栈值要小于*号栈值才能合法。所以栈顶匹配栈顶最可能合法//*栈可以不用在意,因为它可以变成空字符,当上述处理后,根据左括号栈就能判断是否能成功了//贪心策略:遇到右括号优先用左括号进行配对,因为*可以变成空字符不会影响到结果。//反证法:优先使用*栈,那么(*)是错误的,正确结果是true,从而证明不能优先*栈vector<char> left,ans;for(int i=0;i<s.size();i++){if(s[i]=='*') ans.push_back(i);else if(s[i]=='(') left.push_back(i);else if(!left.empty()) left.pop_back();else if(!ans.empty()) ans.pop_back();else return false;}while(!ans.empty() && !left.empty() && left.back()<ans.back()){ans.pop_back();left.pop_back();} return left.empty();}
};
1111. 有效括号的嵌套深度
题意:
给定一组有效括号字符串将它拆成2个不相交(存在第一组就不能存在第二组)的有效括号字符串使max(depth(A), depth(B))最小。A 或 B 中的元素在原字符串中可以不连续。
用0、1标记在哪一组,返回字符串划分情况。
思路:将有效括号字符串尽量均分成两份,这样才能保证max(depth(A), depth(B))最小
class Solution {
public:vector<int> maxDepthAfterSplit(string seq) {//题意:给定一组有效括号字符串将它拆成2个不相交(存在第一组就不能存在第二组)的有效括号字符串使max(depth(A), depth(B))最小。A 或 B 中的元素在原字符串中可以不连续。//用0、1标记在哪一组,返回字符串划分情况。//思路:将有效括号字符串尽量均分成两份,这样才能保证max(depth(A), depth(B))最小int buff=0;vector<int> ret;for(auto x:seq){if(x=='('){buff++;ret.push_back(buff%2);}else{ret.push_back(buff%2);buff--;}}return ret;}
};
1541. 平衡括号字符串的最少插入次数
题意:给定一组只包含括号的字符串,要求以最少的插入次数满足平衡括号。平衡条件:())
思路:
遇到右括号如果后一位也是右括号则不处理,如果不是则需要插入。如果左括号不够也需要进行插入
在第一轮遍历结束后消除了所有右括号,还需要插入2*未配对的左括号次此案满足条件
class Solution {
public:int minInsertions(string s) {//题意:给定一组只包含括号的字符串,要求以最少的插入次数满足平衡括号。平衡条件:())//思路:遇到右括号如果后一位也是右括号则不处理,如果不是则需要插入。如果左括号不够也需要进行插入//在第一轮遍历结束后消除了所有右括号,还需要插入2*未配对的左括号次此案满足条件int buff=0,ret=0;for(int i=0;i<s.size();i++){if(s[i]=='(') buff++;else if(buff){buff--;if(i+1<s.size() && s[i+1]==')') i++;else ret++;}else{ret++;buff++;i--;}}return buff*2+ret;}
};