括号补全问题
一、问题重现
问题描述
小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:
- 它是一个空字符串;
- 它可以写成两个有效字符串的连接形式,即
AB; - 它可以写成
(A)的形式,其中A是有效字符串。
在每次操作中,小R可以在字符串的任意位置插入一个括号。你需要帮小R计算出,最少需要插入多少个括号才能使括号字符串 s 有效。
例如:当 s = "())" 时,小R需要插入一个左括号使字符串有效,结果为 1。
测试样例
样例1:
输入:
s = "())"
输出:1
样例2:
输入:
s = "((("
输出:3
样例3:
输入:
s = "()"
输出:0
样例4:
输入:
s = "()))(("
输出:4
二、解题思路
算法步骤
-
初始化:
res用于记录需要插入的括号数量,初始值为0。st是一个栈,用于存储左括号(。
-
遍历字符串:
- 使用
for循环遍历字符串s中的每一个字符。
- 使用
-
处理左括号
(:- 如果当前字符是左括号
(,将其压入栈st中。
- 如果当前字符是左括号
-
处理右括号
):-
如果当前字符是右括号
),首先检查栈是否为空:-
如果栈为空,说明需要插入一个左括号来匹配这个右括号,因此
res增加1,并跳过当前循环。 -
如果栈不为空,检查栈顶元素是否是左括号
(:-
如果是左括号
(,弹出栈顶元素(匹配成功)。 -
如果不是左括号
(,弹出栈顶元素,并进一步检查栈是否为空:- 如果栈为空,
res增加1。 - 如果栈不为空,再次弹出栈顶元素。
- 如果栈为空,
-
-
-
-
处理其他字符:
-
如果当前字符既不是左括号
(也不是右括号),检查栈是否为空:- 如果栈为空,将当前字符压入栈中。
- 如果栈不为空且栈顶元素不是左括号
(,弹出栈顶元素。
-
-
剩余括号处理:
- 遍历完字符串后,栈中剩余的左括号需要相应数量的右括号来匹配,因此将栈的大小加到
res上。
- 遍历完字符串后,栈中剩余的左括号需要相应数量的右括号来匹配,因此将栈的大小加到
-
返回结果:
- 返回
res,即最少需要插入的括号数量。
- 返回
三、代码实现
int solution(const std::string &s) {
int res = 0;
stack<char> st;
for (char c : s) {
if (c == '(') {
st.push(c);
} else if (c == ')') {
if (!st.empty() && st.top() == '(') {
st.pop();
} else {
res++;
}
}
}
res += st.size();
return res;
}
四、算法复杂度分析
- 时间复杂度:
O(n),其中n是字符串s的长度。我们只需要遍历字符串一次。 - 空间复杂度:
O(n),在最坏情况下,栈st可能存储所有字符。