题目
如果知识判断合法括号,以及一个左括号对应一个右括号的最少插入次数,都是比较简单的。本题的难点在于:任何左括号"(“必须对应两个连续的右括号”)"。
题解
先写出题目的代码框架:
def minInsertions(s: str) -> int:res = 0 # 记录操作数needs = 0 # 记录对右括号的需求数for i in s:if i == '(':needs += 2elif i == ')':needs -= 1return res + needs
现在考虑什么时候需要插入操作呢?
- 先看遇到右括号的时候(这个比较简单),如果needs为负数了,说明右括号太多了,需要补一个左括号啦!
if needs == -1:# 补左括号,操作数+1res += 1# 补了一个左括号,右括号需求加2needs += 2
- 再看遇到左括号的时候,这里比较难想到:如果needs为奇数了,需要补一个右括号。
if needs % 2 == 1:# 补右括号res += 1needs -= 1
- 为啥needs会为奇数呢,上面1的操作就会带来needs=1的情况,因为我们加了一个左括号,当时右括号又只有1个,所以加完后needs就等于1了。这个时候再遇到左括号,needs也只会2个2个的加,怎么加都是个奇数。
- needs为奇数的时候,我不补一个右括号不行吗?不加的时候可以通过54/102个测试案例,但是下面这个就会报错了:
s = “(()))(()))()())))”
输出1,期望输出4。
我们看一下到底是哪里出了问题,我们列出前5次迭代的res和needs的值,可以看到iter=4的时候出现了needs为奇数的情况,也就是(())),此时我们没有进行处理,当iter=5出现左括号的时候,就直接在needs继续减了。但明显我们应该先补一个右括号才是合法的。
iter | res | needs |
0 | 0 | 2 |
1 | 0 | 4 |
2 | 0 | 3 |
3 | 0 | 2 |
4 | 0 | 1 |
5 | 0 | 3 |
完整代码
def minInsertions(s: str) -> int:res = 0 # 记录操作数needs = 0 # 记录对右括号的需求数for i in s:if i == '(':needs += 2if needs % 2 == 1:# 补右括号一个res += 1needs -= 1elif i == ')':needs -= 1if needs == -1:# 补左括号,操作数+1, needs + 2res += 1needs += 2return res + needs