427括号补全问题|豆包MarsCode AI刷题

45 阅读5分钟

427括号补全问题|豆包MarsCode AI刷题

栈的基本操作

  1. 入栈(Push)

    • 将一个新元素添加到栈的顶端。
    • 这通常意味着栈的容量会增加(如果栈是基于动态数组实现的)或者栈会指向一个新的、未使用的内存位置(如果栈是基于链表实现的)。
  2. 出栈(Pop)

    • 移除并返回栈顶的元素。
    • 这通常意味着栈的顶端指针或索引会向下移动,指向新的栈顶元素。
  3. 查看栈顶元素(Peek或Top)

    • 返回栈顶的元素,但不移除它。
    • 这个操作不会改变栈的状态。
  4. 检查栈是否为空(IsEmpty)

    • 判断栈是否包含任何元素。
    • 如果栈为空,则此操作返回true;否则返回false
  5. 获取栈的大小(Size)

    • 返回栈中当前元素的数量。

栈的应用

栈在多种算法和数据结构问题中发挥着关键作用,包括但不限于:

  • 括号匹配:如之前所讨论的,栈可以用来检查括号字符串是否有效,并计算使字符串有效所需的最少插入括号数量。
  • 表达式求值:在计算后缀表达式(也称为逆波兰表示法)时,栈用于存储操作数和操作符。
  • 递归函数调用:大多数编程语言使用栈来管理递归函数调用的上下文(包括局部变量、返回地址等)。
  • 路径导航:在图形界面中,栈可以用来存储用户的导航历史,以便实现“前进”和“后退”功能。
  • 语法分析:在编译器设计中,栈用于解析和转换源代码中的语法结构。

栈的实现

栈可以通过多种方式实现,包括:

  • 数组:使用固定大小的数组作为栈的底层存储,并通过一个索引来跟踪栈顶的位置。这种实现方式在访问栈顶元素时具有O(1)的时间复杂度,但在栈满时插入新元素会导致栈溢出。
  • 动态数组:类似于数组,但大小可以根据需要动态调整。这种实现方式在大多数情况下也具有O(1)的时间复杂度,但在调整数组大小时可能会有额外的开销。
  • 链表:使用链表节点来存储栈的元素,每个节点都指向下一个节点。这种实现方式在插入和删除操作时具有O(1)的时间复杂度,但可能需要额外的内存来存储指针。

问题描述

小R有一个括号字符串 s,他想知道这个字符串是否是有效的。一个括号字符串如果满足以下条件之一,则是有效的:

  1. 它是一个空字符串;
  2. 它可以写成两个有效字符串的连接形式,即 AB
  3. 它可以写成 (A) 的形式,其中 A 是有效字符串。

在每次操作中,小R可以在字符串的任意位置插入一个括号。你需要帮小R计算出,最少需要插入多少个括号才能使括号字符串 s 有效。

例如:当 s = "())" 时,小R需要插入一个左括号使字符串有效,结果为 1


测试样例

样例1:

输入:s = "())"
输出:1

样例2:

输入:s = "((("
输出:3

样例3:

输入:s = "()"
输出:0

样例4:

输入:s = "()))(("
输出:4

解答

我们遍历字符串 s 中的每个字符。

  • 如果字符是左括号 '(',我们将其压入栈中。

  • 如果字符是右括号 ')',我们检查栈是否为空:

    • 如果栈不为空,我们弹出一个左括号,表示它们已经匹配。
    • 如果栈为空,意味着我们遇到了一个无法匹配的右括号,因此我们需要插入一个左括号来匹配它,并将 leftToInsert 加一。

测试样例解析

  1. 输入:"())"

    • 遍历字符串:遇到 (,压入栈;遇到 ),弹出栈;再遇到 ),栈为空,需要插入一个左括号。
    • 结果:需要插入1个左括号,栈中无剩余左括号,所以不需要插入右括号。总插入数为1。
  2. 输入:"((("

    • 遍历字符串:遇到三个 (,都压入栈。
    • 结果:无需插入左括号,但栈中有三个未匹配的左括号,需要插入三个右括号。总插入数为3。
  3. 输入:"()"

    • 遍历字符串:遇到 (,压入栈;遇到 ),弹出栈。
    • 结果:无需插入任何括号。总插入数为0。
  4. 输入:"()))(("

    • 遍历字符串:遇到 (,压入栈;遇到两个 ),弹出栈一次,另一次需要插入一个左括号;再遇到 (,压入栈;遇到 ),弹出栈;遇到两个 (,都压入栈。
    • 结果:需要插入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;
}