题目
标题和出处
标题:使括号有效的最少添加
难度
4 级
题目描述
要求
一个括号字符串是有效的,当且仅当满足下列条件之一:
- 字符串是一个空字符串;
- 字符串可以写为 AB \texttt{AB} AB( A \texttt{A} A 与 B \texttt{B} B 字符串连接),其中 A \texttt{A} A 和 B \texttt{B} B 都是有效括号字符串;
- 字符串可以写为 (A) \texttt{(A)} (A),其中 A \texttt{A} A 是一个有效括号字符串。
给定一个括号字符串 s \texttt{s} s。每一步添加可以在字符串的任意位置插入一个括号。
- 例如, s = "()))" \texttt{s = "()))"} s = "()))",可以插入一个左括号得到 "(()))" \texttt{"(()))"} "(()))" 或者插入一个右括号得到 "())))" \texttt{"())))"} "())))"。
返回使 s \texttt{s} s 有效的最少添加次数。
示例
示例 1:
输入:
s
=
"())"
\texttt{s = "())"}
s = "())"
输出:
1
\texttt{1}
1
示例 2:
输入:
s
=
"((("
\texttt{s = "((("}
s = "((("
输出:
3
\texttt{3}
3
示例 3:
输入:
"()"
\texttt{"()"}
"()"
输出:
0
\texttt{0}
0
示例 4:
输入:
"()))(("
\texttt{"()))(("}
"()))(("
输出:
4
\texttt{4}
4
数据范围
- 1 ≤ s.length ≤ 1000 \texttt{1} \le \texttt{s.length} \le \texttt{1000} 1≤s.length≤1000
- s[i] \texttt{s[i]} s[i] 是 ‘(’ \texttt{`('} ‘(’ 或 ‘)’ \texttt{`)'} ‘)’
解法一
思路和算法
有效的括号字符串中,左括号和右括号成对出现,在每对左右括号中,左括号在右括号的左边。
如果一个左括号右边没有右括号匹配,或者一个右括号左边没有左括号匹配,则需要插入相应的括号,才能使括号字符串有效。
可以使用栈存储左括号,从左到右遍历字符串 s s s,计算使字符串 s s s 有效的最少添加次数。对于每个字符,进行如下操作:
-
遇到左括号,则将左括号入栈;
-
遇到右括号且栈不为空,则将栈顶的左括号出栈,表示当前的右括号和栈顶的左括号匹配;
-
遇到右括号且栈为空,则当前的右括号没有左括号匹配,因此需要插入一个左括号,将添加次数加 1 1 1。
遍历结束之后,如果栈不为空,则栈内的每个左括号都没有右括号匹配,对于栈内的每个左括号都需要插入一个右括号,因此将添加次数加上栈内左括号个数。
最终得到的添加次数即为使字符串 s s s 有效的最少添加次数。
注意上述操作中,只计算需要插入的左括号个数和右括号个数,没有考虑插入括号的位置,这是因为每一步添加可以在字符串的任意位置插入一个括号,对于每个右括号,总能在其左边找到一个位置插入左括号,对于每个左括号,总能在其右边找到一个位置插入右括号。
代码
class Solution {
public int minAddToMakeValid(String s) {
int add = 0;
Deque<Character> stack = new ArrayDeque<Character>();
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == '(') {
stack.push(c);
} else {
if (!stack.isEmpty()) {
stack.pop();
} else {
add++;
}
}
}
add += stack.size();
return add;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,每次入栈和出栈操作的时间都是 O ( 1 ) O(1) O(1)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。空间复杂度主要取决于栈空间,栈内的元素个数为 O ( n ) O(n) O(n)。
解法二
思路和算法
也可以不用栈,而是使用计数的方式计算使字符串 s s s 有效的最少添加次数。
使用 add \textit{add} add 记录添加次数,使用 count \textit{count} count 记录未匹配的左括号的数量,初始时 add = count = 0 \textit{add} = \textit{count} = 0 add=count=0。
从左到右遍历字符串 s s s,对于每个字符,进行如下操作:
-
遇到左括号,则将 count \textit{count} count 加 1 1 1;
-
遇到右括号且 count > 0 \textit{count} > 0 count>0,则将 count \textit{count} count 减 1 1 1;
-
遇到右括号且 count = 0 \textit{count} = 0 count=0,则当前的右括号没有左括号匹配,因此需要插入一个左括号,将 add \textit{add} add 加 1 1 1。
遍历结束之后, count \textit{count} count 为尚未匹配的左括号的数量,对于每个尚未匹配的左括号都需要插入一个右括号,因此将 add \textit{add} add 加 count \textit{count} count。
最终得到的 add \textit{add} add 即为使字符串 s s s 有效的最少添加次数。
代码
class Solution {
public int minAddToMakeValid(String s) {
int add = 0;
int count = 0;
int length = s.length();
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == '(') {
count++;
} else {
if (count > 0) {
count--;
} else {
add++;
}
}
}
add += count;
return add;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次,每次更新计数的时间都是 O ( 1 ) O(1) O(1)。
-
空间复杂度: O ( 1 ) O(1) O(1)。