427括号补全问题|豆包MarsCode AI刷题
栈
栈的基本操作
-
入栈(Push) :
- 将一个新元素添加到栈的顶端。
- 这通常意味着栈的容量会增加(如果栈是基于动态数组实现的)或者栈会指向一个新的、未使用的内存位置(如果栈是基于链表实现的)。
-
出栈(Pop) :
- 移除并返回栈顶的元素。
- 这通常意味着栈的顶端指针或索引会向下移动,指向新的栈顶元素。
-
查看栈顶元素(Peek或Top) :
- 返回栈顶的元素,但不移除它。
- 这个操作不会改变栈的状态。
-
检查栈是否为空(IsEmpty) :
- 判断栈是否包含任何元素。
- 如果栈为空,则此操作返回
true;否则返回false。
-
获取栈的大小(Size) :
- 返回栈中当前元素的数量。
栈的应用
栈在多种算法和数据结构问题中发挥着关键作用,包括但不限于:
- 括号匹配:如之前所讨论的,栈可以用来检查括号字符串是否有效,并计算使字符串有效所需的最少插入括号数量。
- 表达式求值:在计算后缀表达式(也称为逆波兰表示法)时,栈用于存储操作数和操作符。
- 递归函数调用:大多数编程语言使用栈来管理递归函数调用的上下文(包括局部变量、返回地址等)。
- 路径导航:在图形界面中,栈可以用来存储用户的导航历史,以便实现“前进”和“后退”功能。
- 语法分析:在编译器设计中,栈用于解析和转换源代码中的语法结构。
栈的实现
栈可以通过多种方式实现,包括:
- 数组:使用固定大小的数组作为栈的底层存储,并通过一个索引来跟踪栈顶的位置。这种实现方式在访问栈顶元素时具有O(1)的时间复杂度,但在栈满时插入新元素会导致栈溢出。
- 动态数组:类似于数组,但大小可以根据需要动态调整。这种实现方式在大多数情况下也具有O(1)的时间复杂度,但在调整数组大小时可能会有额外的开销。
- 链表:使用链表节点来存储栈的元素,每个节点都指向下一个节点。这种实现方式在插入和删除操作时具有O(1)的时间复杂度,但可能需要额外的内存来存储指针。
问题描述
小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:
- 它是一个空字符串;
- 它可以写成两个有效字符串的连接形式,即
AB; - 它可以写成
(A)的形式,其中A是有效字符串。
在每次操作中,小R可以在字符串的任意位置插入一个括号。你需要帮小R计算出,最少需要插入多少个括号才能使括号字符串 s 有效。
例如:当 s = "())" 时,小R需要插入一个左括号使字符串有效,结果为 1。
测试样例
样例1:
输入:
s = "())"
输出:1
样例2:
输入:
s = "((("
输出:3
样例3:
输入:
s = "()"
输出:0
样例4:
输入:
s = "()))(("
输出:4
解答
我们遍历字符串 s 中的每个字符。
-
如果字符是左括号
'(',我们将其压入栈中。 -
如果字符是右括号
')',我们检查栈是否为空:- 如果栈不为空,我们弹出一个左括号,表示它们已经匹配。
- 如果栈为空,意味着我们遇到了一个无法匹配的右括号,因此我们需要插入一个左括号来匹配它,并将
leftToInsert加一。
测试样例解析
-
输入:
"())"- 遍历字符串:遇到
(,压入栈;遇到),弹出栈;再遇到),栈为空,需要插入一个左括号。 - 结果:需要插入1个左括号,栈中无剩余左括号,所以不需要插入右括号。总插入数为1。
- 遍历字符串:遇到
-
输入:
"((("- 遍历字符串:遇到三个
(,都压入栈。 - 结果:无需插入左括号,但栈中有三个未匹配的左括号,需要插入三个右括号。总插入数为3。
- 遍历字符串:遇到三个
-
输入:
"()"- 遍历字符串:遇到
(,压入栈;遇到),弹出栈。 - 结果:无需插入任何括号。总插入数为0。
- 遍历字符串:遇到
-
输入:
"()))(("- 遍历字符串:遇到
(,压入栈;遇到两个),弹出栈一次,另一次需要插入一个左括号;再遇到(,压入栈;遇到),弹出栈;遇到两个(,都压入栈。 - 结果:需要插入1个左括号来匹配第二个
),栈中剩余两个未匹配的左括号,需要插入两个右括号。总插入数为4。
- 遍历字符串:遇到
通过这些步骤,我们可以清晰地看到代码是如何工作的,以及它是如何计算出每个测试用例所需的最少插入括号数量的。
#include <iostream>
#include <string>
#include <stack>
int solution(const std::string& s) {
std::stack<char> stk;
int leftToInsert = 0; // 记录需要插入的左括号数量
for (char c : s) {
if (c == '(') {
stk.push(c);
} else if (c == ')') {
if (!stk.empty()) {
stk.pop(); // 匹配一个左括号
} else {
leftToInsert++; // 需要插入一个左括号
}
}
}
// 栈中剩余的每个左括号都需要一个右括号来匹配
int rightToInsert = stk.size();
// 返回需要插入的总括号数量
return leftToInsert + rightToInsert;
}
int main() {
std::cout << solution("())") << std::endl; // 输出1
std::cout << solution("(((") << std::endl; // 输出3
std::cout << solution("()") << std::endl; // 输出0
std::cout << solution("()))((") << std::endl; // 输出4
return 0;
}