每日算法刷题Day55:7.27:leetcode 复习完第K小/大+栈4道题,用时1h50min
8. 1963. 使字符串平衡的最小交换次数(中等,学习)
1963. 使字符串平衡的最小交换次数 - 力扣(LeetCode)
思想
1.给你一个字符串 s
,下标从 0 开始 ,且长度为偶数 n
。字符串 恰好 由 n / 2
个开括号 '['
和 n / 2
个闭括号 ']'
组成。
只有能满足下述所有条件的字符串才能称为 平衡字符串 :
- 字符串是一个空字符串,或者
- 字符串可以记作
AB
,其中A
和B
都是 平衡字符串 ,或者 - 字符串可以写成
[C]
,其中C
是一个 平衡字符串 。
你可以交换 任意 两个下标所对应的括号 任意 次数。
返回使s
变成 平衡字符串 所需要的 最小 交换次数。
2.思考一个问题,什么时候才必须要交换呢?若当前左括号的个数大于等于右括号,则肯定有一种匹配方式不用交换就能实现平衡,而左括号个数小于右括号,则当前必然有右括号无法与左边的(括号匹配性质决定) 左括号匹配,那这个转化为分值问题就是score>=0
时无需交换,score<0
时需交换
那右括号跟右边的哪个左括号交换呢?因为右括号让score-1
,而score<0
时才必须要交换,所以让这个右括号尽可能地晚出现,所以应该选最右边未替换过的左括号替换过来。
那真的要显式替换吗?这个替换带来的影响是这个位置变成左括号,score+1
,且交换次数加1,只需要维护这两个变量即可,那交换后的右括号不是没有减1了吗?没有影响,因为交换的是最右边未替换过的左括号,所以遍历到这里必然已经实现平衡了,无需交换了,对交换次数没有影响。
代码
class Solution {
public:int minSwaps(string s) {int n = s.size();int score = 0, res = 0;for (int i = 0; i < n; ++i) {if (s[i] == '[')++score;else if (score > 0)--score;else {++score;++res;}}return res;}
};
9. 678. 有效的括号字符串(中等,学习)
678. 有效的括号字符串 - 力扣(LeetCode)
思想
1.给你一个只包含三种字符的字符串,支持的字符类型分别是 '('
、')'
和 '*'
。请你检验这个字符串是否为有效字符串,如果是 有效 字符串返回 true
。
有效 字符串符合如下规则:
- 任何左括号
'('
必须有相应的右括号')'
。 - 任何右括号
')'
必须有相应的左括号'('
。 - 左括号
'('
必须在对应的右括号之前')'
。 '*'
可以被视为单个右括号')'
,或单个左括号'('
,或一个空字符串""
。
2.注意到若为*()
则这个*
号起不到用处,所以一开始想维护和左括号匹配的星号和右括号匹配的星号数量,但是一个星号只有用一次,不对,且这个个数和score
是两个变量。
学习维护未匹配的左括号的数量score
,但因为星号有三种作用,所以要维护未匹配的左括号的数量的最大值(星号当左括号)和最小值(星号当右括号)- 遇到左括号,两个都加1
- 遇到星号,最大值加1,最小值减1,但不能小于0(若此时最小值为0,则说明左侧已经平衡,此时星号应当作为空字符串)
- 遇到右括号,两个都减1,若最大值小于0,则说明左边左括号数量最多也无法与右括号匹配,肯定不有效
最终还要判断最小值是否是0,若大于0,则说明星号尽可能地变成右括号也无法全部与左括号匹配,不有效
代码
class Solution {
public:bool checkValidString(string s) {int n = s.size();int mincnt = 0, maxcnt = 0;for (int i = 0; i < n; ++i) {if (s[i] == '(') {++maxcnt;++mincnt;} else if (s[i] == '*') {++maxcnt; // 充当左括号mincnt =max(mincnt - 1,0); // 充当右括号,但是如果左边都没左括号了,应该变成0} else {if (maxcnt <= 0)return false;--maxcnt;mincnt = max(mincnt - 1, 0);}}return mincnt == 0;}
};
10. 1111. 有效括号的嵌套深度(中等,学习)
1111. 有效括号的嵌套深度 - 力扣(LeetCode)
思想
1.给你一个「有效括号字符串」 seq
,请你将其分成两个不相交的有效括号字符串,A
和 B
,并使这两个字符串的深度最小。
- 不相交:每个
seq[i]
只能分给A
和B
二者中的一个,不能既属于A
也属于B
。 A
或B
中的元素在原字符串中可以不连续。A.length + B.length = seq.length
- 深度最小:
max(depth(A), depth(B))
的可能取值最小。
划分方案用一个长度为 seq.length
的答案数组 answer
表示,编码规则如下:
answer[i] = 0
,seq[i]
分给A
。answer[i] = 1
,seq[i]
分给B
。
如果存在多个满足要求的答案,只需返回其中任意 一个 即可。
2.首先将有效括号字符串分成两个有效括号字符串,则肯定每个左右括号数量相等,要让两个嵌套深度最大值最小,所以尽可能平均当前嵌套深度,观察一组数据的嵌套深度:
括号序列 ( ( ) ( ( ) ) ( ) )
下标编号 0 1 2 3 4 5 6 7 8 9
嵌套深度 1 2 2 2 3 3 2 2 2 1
所以嵌套深度为奇数的括号对放一组,偶数的括号对放一组即可
学习如何记录嵌套深度:
- 左括号先
++d
,然后得到嵌套深度 - 右括号先记录嵌套深度,再
--d
代码
class Solution {
public:vector<int> maxDepthAfterSplit(string seq) {int n = seq.size();vector<int> res;int d = 0;for (int i = 0; i < n; ++i) {if (seq[i] == '(') {// 先增加嵌套深度,得到当前嵌套深度++d;res.push_back(d % 2);} else {// 先记录当前嵌套深度,再减res.push_back(d % 2);--d;}}return res;}
};
12. 1541. 平衡括号字符串的最少插入次数(中等)
1541. 平衡括号字符串的最少插入次数 - 力扣(LeetCode)
思想
1.给你一个括号字符串 s
,它只包含字符 '('
和 ')'
。一个括号字符串被称为平衡的当它满足:
- 任何左括号
'('
必须对应两个连续的右括号'))'
。 - 左括号
'('
必须在对应的连续两个右括号'))'
之前。
比方说"())"
,"())(())))"
和"(())())))"
都是平衡的,")()"
,"()))"
和"(()))"
都是不平衡的。
你可以在任意位置插入字符 ‘(’ 和 ‘)’ 使字符串平衡。
请你返回让s
平衡的最少插入次数。
2.改变在任何左括号'('
必须对应两个连续的右括号'))'
,所以还是拿score
来维护未匹配的左括号个数,然后模拟分类讨论的时候细心一点即可
代码
class Solution {
public:int minInsertions(string s) {int n = s.size(), score = 0, res = 0;for (int i = 0; i < n; ++i) {if (s[i] == '(')score += 1;else {// 不需要补左括号if (score > 0) {if (i + 1 < n && s[i + 1] == ')') {++i;} else {// 补右括号++res;}// score为非负--score;} // 需要补左括号else {if (i + 1 < n && s[i + 1] == ')') {++i;// 补左括号++res;} else {// 补左括号和右括号res += 2;}}}}// 一个左括号匹配两个右括号res += score * 2;return res;}
};