问题描述
小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:
- 它是一个空字符串;
- 它可以写成两个有效字符串的连接形式,即
AB; - 它可以写成
(A)的形式,其中A是有效字符串。
在每次操作中,小R可以在字符串的任意位置插入一个括号。你需要帮小R计算出,最少需要插入多少个括号才能使括号字符串 s 有效。
例如:当 s = "())" 时,小R需要插入一个左括号使字符串有效,结果为 1。
测试样例
样例1:
输入:s = "())"
输出:1
样例2:
输入:s = "((("
输出:3
样例3:
输入:s = "()"
输出:0
样例4:
输入:s = "()))(("
输出:4
要解决这个括号补全问题,我们需要确保字符串中的每个括号都是有效配对的。具体来说,我们要判断给定的字符串中缺少多少个括号,以使其成为一个有效的括号字符串。我们可以采用一种栈的思想来解决这个问题,或者直接用两个计数器来模拟括号的匹配过程。
问题分析
一个有效的括号字符串需要满足以下条件:
- 每个左括号
(都必须有一个右括号)来与之配对。 - 在字符串的过程中,任何时刻左括号的数量不能少于右括号的数量。
思路
我们可以使用两个计数器:
left_needed:用于记录当前缺少的左括号数量(即多余的右括号数量)。每当遇到一个右括号,而当前没有对应的左括号时,我们就增加这个计数器。right_needed:用于记录当前缺少的右括号数量(即多余的左括号数量)。每当遇到一个左括号时,我们就增加这个计数器。
具体步骤:
- 初始化两个计数器:
left_needed和right_needed都为 0。 - 遍历字符串:
-
- 如果遇到左括号
(,说明需要一个右括号来配对,所以增加right_needed。 - 如果遇到右括号
),检查是否有未配对的左括号。如果有,减少right_needed,否则增加left_needed,表示缺少一个左括号。
- 如果遇到左括号
- 最后,
left_needed和right_needed的总和即为需要补充的括号数量。
代码实现
def minAddToMakeValid(s):
left_needed = 0 # 记录缺少的左括号
right_needed = 0 # 记录缺少的右括号
for char in s:
if char == '(':
right_needed += 1 # 需要一个右括号来配对
elif char == ')':
if right_needed > 0:
right_needed -= 1 # 找到一个配对的右括号
else:
left_needed += 1 # 没有配对的左括号,增加一个左括号
return left_needed + right_needed # 总共需要补充的括号数
# 测试样例
print(minAddToMakeValid("())")) # 输出: 1
print(minAddToMakeValid("(((")) # 输出: 3
print(minAddToMakeValid("()")) # 输出: 0
print(minAddToMakeValid("()))((")) # 输出: 4
解释
- 样例 1:
s = "())":
-
- 第一个右括号没有对应的左括号,因此需要一个左括号,
left_needed= 1,最终需要补充 1 个括号。
- 第一个右括号没有对应的左括号,因此需要一个左括号,
- 样例 2:
s = "(((":
-
- 有三个左括号,但是没有右括号配对,因此需要 3 个右括号,
right_needed= 3,最终需要补充 3 个括号。
- 有三个左括号,但是没有右括号配对,因此需要 3 个右括号,
- 样例 3:
s = "()":
-
- 这个字符串已经是有效的,因此不需要任何补充括号,返回 0。
- 样例 4:
s = "()))((":
-
- 在遍历时:
-
-
- 右括号多于左括号,需要 2 个左括号补充。
- 左括号多于右括号,需要 2 个右括号补充。
-
-
- 总共需要补充 4 个括号。
时间复杂度
- 时间复杂度:
O(n),其中n是字符串的长度。我们只需要遍历一次字符串,进行常数时间的操作。 - 空间复杂度:
O(1),我们只使用了常数空间来存储计数器。
总结
这个问题可以通过模拟括号配对的过程来解决,使用两个计数器分别统计缺少的左括号和右括号。每遍历一次字符串,我们更新这些计数器,最终的结果就是需要插入的最少括号数。