问题分析
我们需要检查一个括号字符串是否有效。一个有效的括号字符串满足以下条件之一:
- 它是一个空字符串。
- 它是两个有效字符串的连接。
- 它是一个左括号和右括号包围的有效字符串。
对于给定的字符串 s,我们需要计算出最少需要插入多少个括号才能使字符串有效。操作允许在任意位置插入一个括号。目标是确保括号匹配且没有多余的左括号或右括号。
思路解析
-
左括号和右括号的匹配:
- 每个左括号
(必须有一个右括号)来配对。 - 如果遇到一个右括号
)时,若当前没有左括号可以匹配,则说明此时需要插入一个左括号(。 - 如果遇到一个左括号
(,则记录一个待配对的左括号,直到遇到一个右括号)来消耗它。
- 每个左括号
-
如何插入括号:
- 当遇到没有匹配的右括号
),需要插入左括号(来与之匹配。 - 最终,栈中剩余的左括号
(,说明还需要插入右括号)来配对这些左括号。
- 当遇到没有匹配的右括号
解法实现
通过栈来实现括号匹配的思路。每当遇到一个左括号时,推入栈中。当遇到右括号时,尝试从栈中弹出一个左括号,表示匹配成功。如果栈为空,则表示当前右括号没有匹配的左括号,我们就需要插入一个左括号。同样,栈中的剩余左括号数量表示需要插入多少个右括号。
代码详解
def solution(s: str) -> int:
# 初始化栈来帮助我们匹配括号
stack = []
# 记录需要插入的括号数量
insert_count = 0
# 遍历字符串中的每一个字符
for char in s:
if char == '(':
# 遇到左括号,入栈
stack.append(char)
elif char == ')':
if stack:
# 如果栈非空,弹出栈顶元素(匹配一个左括号)
stack.pop()
else:
# 如果栈为空,表示需要插入一个左括号
insert_count += 1
# 最后,栈中剩余的左括号数量是需要插入右括号的数量
insert_count += len(stack)
return insert_count
if __name__ == '__main__':
print(solution("()") == 0) # 输出 0
print(solution("(((") == 3) # 输出 3
print(solution("())") == 1) # 输出 1
print(solution("()))((") == 4) # 输出 4
复杂度分析
-
时间复杂度:
- 遍历字符串一次,时间复杂度为 O(n),其中 n 是字符串
s的长度。 - 每次操作(入栈或出栈)是 O(1),因此总的时间复杂度为 O(n)。
- 遍历字符串一次,时间复杂度为 O(n),其中 n 是字符串
-
空间复杂度:
- 栈的空间复杂度为 O(n),最坏情况下(例如所有字符都是左括号),栈中需要存储 n 个元素。
- 因此,总的空间复杂度为 O(n)。
样例分析
样例 1
输入:s = "())"
- 第一个字符是
(,入栈,栈变为["("]。 - 第二个字符是
),栈非空,弹出一个左括号,栈变为空。 - 第三个字符是
),栈为空,需要插入一个左括号来与之匹配。
因此,最少需要插入 1 个左括号,输出 1。
样例 2
输入:s = "((("
- 所有的字符都是左括号
(,所以栈将一直增加,最终栈中会有 3 个左括号。 - 因此,最少需要插入 3 个右括号来与这些左括号匹配。
输出 3。
样例 3
输入:s = "()"
- 第一个字符是
(,入栈,栈变为["("]。 - 第二个字符是
),栈非空,弹出一个左括号,栈变为空。
此时字符串已经是有效的,不需要插入任何括号,输出 0。
样例 4
输入:s = "()))(("
- 第一个字符是
), 栈为空,需要插入一个左括号,插入后栈为["("]。 - 第二个字符是
), 栈非空,弹出一个左括号,栈变为空。 - 第三个字符是
), 栈为空,需要插入一个左括号,插入后栈为["("]。 - 第四个字符是
), 栈非空,弹出一个左括号,栈变为空。 - 第五个字符是
(, 入栈,栈变为["("]。 - 第六个字符是
(, 入栈,栈变为["(", "("]。
栈中有 2 个左括号,需要插入 2 个右括号,已经插入了 2 个左括号,所以需要插入 4 个括号。
输出 4。
总结
本题要求计算最少需要插入多少个括号来使得给定的括号字符串有效。通过栈来模拟括号的匹配过程,每次遇到不匹配的右括号时插入一个左括号,每次栈中还有剩余的左括号时需要插入对应数量的右括号。时间复杂度为 O(n),空间复杂度为 O(n),是一种高效的解决方案。