[M模拟] lc2116. 判断一个括号字符串是否有效(思维+括号匹配问题+问题分析+代码实现)
文章目录
- 1. 题目来源
- 前置题目:
- 2. 题目解析
1. 题目来源
链接:2116. 判断一个括号字符串是否有效
前置题目:
题单:
- 待补充
2. 题目解析
这个题目,灵神 的分析十分十分巧妙,很值得多读几遍。也是从本题中,能窥看到 括号匹配 问题的内在本质。
方法一:一次遍历。
- 问题分析:详细的可以直接移步灵神题解。
2025年03月23日16:44:59
记录一下自己对本题的理解:
- 括号匹配问题,在任意下标下,只用关心左括号的未匹配个数即可,记为 C。
- 遇到左括号则 +1,右括号则 -1。
- 如果中途 C < 0 则说明右括号大于了左括号个数,不匹配。
- 否则遍历完毕仅需判断 C==0 即可得到整个括号序列是否匹配。
以上是常规的匹配过程,但对本题来说,有部分下标可以变成左括号、右括号 其中一种。
- 那么对于 C 的变化,就不是一个确定的值,而是一个 取值集合。
- 遍历完毕后,最终这个取值集合里面包含了数值 0,则说明有解,否则无解。
至于代码实现过程,不需要真的去维护这个取值集合。而是关注这个集合中的最大值、最小值即可。
- 最大值在变化过程中 < 0,说明前缀的右括号过多,一定无解。
- 最小值在变化过程中 < 0,说明取值集合可能是 {0,2,4} 向 {1,3} 这样子转变。那么就需要将最小值赋值为 1。
- 最后判断最小值是否等于 0 即可。
注意这个集合中的数字,都是连续奇数、连续偶数,且都是大于等于 0 的,这个可以通过简单的数学归纳法证明。
这个写法十分巧妙,且容易理解,包括灵神的例子也十分巧妙。
先记录在此,看看什么时候复习的时候想不起来了,再来复习hh…
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
func canBeValid(s string, locked string) bool {
n := len(s)
if n % 2 != 0 { // 如果是奇数长度,一定无解
return false
}
mn, mx := 0, 0 // 左括号的取值集合的最大值、最小值
for i, v := range s {
if locked[i] == '1' { // 如果它不可变
d := 1
if v == ')' {
d = -1
}
mx += d // 记录最大值变化
if mx < 0 { // 如果左括号最大值都小于 0,说明右括号过多,一定无解
return false
}
mn += d // 记录最小值变化
} else { // 该位置可变
mx ++ // 变左括号,左括号未匹配的最大值 ++
mn -- // 变右括号,左括号未匹配的最小值 --
}
// 如果左括号最小值过程中 < 0。实际上现在的结果集合是从 {0,2,4} 变为了 {1,3} 这样子
// 因为上述在不可变的情况下,已经判断了无解情况。
// 在可变情况下,一定可以将 mn 变为 1。
if mn < 0 {
mn = 1
}
}
return mn == 0
}