Medium
题目描述
当且仅当以下情况时,括号字符串才有效:
- 它是空字符串
- 它可以被写成 AB(A 连接 B),其中 A 和 B 都是有效字符串,或
- 它可以被写成 (A),其中 A 是有效字符串
给你一个括号字符串 s。在一次操作中,你可以在字符串的任何位置插入一个括号。
例如,如果 s = “())",你可以插入一个开括号变成 “(())” 或者插入一个闭括号变成 “()))))"。
返回使 s 有效所需的最少插入次数。
示例 1:
输入: s = "())"
输出: 1
示例 2:
输入: s = "((("
输出: 3
提示:
- 1 <= s.length <= 1000
- s[i] 是 ‘(’ 或 ‘)’
解题思路
这道题要求计算使括号字符串有效所需的最少添加次数。我们可以使用贪心策略来解决。
核心思路: 遍历字符串,维护两个计数器:
open:记录未匹配的左括号数量close:记录无法匹配的右括号数量
算法流程:
- 遇到
(:增加open计数 - 遇到
):- 如果有未匹配的左括号(
open > 0),则匹配一对,open减1 - 否则这是一个多余的右括号,
close增加1
- 如果有未匹配的左括号(
为什么这样可行?
open记录了需要添加右括号的数量close记录了需要添加左括号的数量- 总的添加次数就是
open + close
这种贪心策略是最优的,因为我们总是优先匹配已有的括号,只有在无法匹配时才计入需要添加的数量。
时间复杂度: O(n),只需遍历一次字符串 空间复杂度: O(1),只使用常数额外空间
代码实现
class Solution {
public:
int minAddToMakeValid(string s) {
int open = 0, close = 0;
for (char c : s) {
if (c == '(') {
open++;
} else {
if (open > 0) {
open--;
} else {
close++;
}
}
}
return open + close;
}
};
class Solution:
def minAddToMakeValid(self, s: str) -> int:
open_count = 0
close_count = 0
for c in s:
if c == '(':
open_count += 1
else:
if open_count > 0:
open_count -= 1
else:
close_count += 1
return open_count + close_count
public class Solution {
public int MinAddToMakeValid(string s) {
int open = 0, close = 0;
foreach (char c in s) {
if (c == '(') {
open++;
} else {
if (open > 0) {
open--;
} else {
close++;
}
}
}
return open + close;
}
}
var minAddToMakeValid = function(s) {
let open = 0;
let close = 0;
for (let char of s) {
if (char === '(') {
open++;
} else if (char === ')') {
if (open > 0) {
open--;
} else {
close++;
}
}
}
return open + close;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n),其中 n 是字符串长度,需要遍历字符串一次 |
| 空间复杂度 | O(1),只使用常数个变量存储计数器 |