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

158 阅读3分钟

一、括号补全问题

问题描述

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

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

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

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

测试样例

样例1:

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

样例2:

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

样例3:

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

样例3:

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

二、解题思路

  1. 使用栈:栈可以帮助我们追踪未匹配的左括号。
  2. 遍历字符串:遍历字符串中的每个字符,如果是左括号,则将其压入栈中;如果是右括号,则检查栈是否为空。如果栈为空,说明需要插入一个左括号;如果栈不为空,则弹出一个左括号。
  3. 计算插入的括号数:遍历结束后,栈中剩余的左括号数量就是需要插入的右括号的数量。

三、solution函数

import java.util.Stack;

public class Main {
    public static int solution(String s) {
        // 创建一个栈来存储左括号
        Stack<Character> stack = new Stack<>();
        int count = 0;

        for (char c : s.toCharArray()) {
            if (c == '(') {
                stack.push(c);
            } else {
                // 如果是右括号且栈为空,说明需要插入一个左括号,`count` 加一
                if (stack.isEmpty()) {
                    count++;
                } else {
                    stack.pop();
                }
            }
        }

        // 栈中剩余的左括号数量就是需要插入的右括号的数量
        count += stack.size();
        return count;
    }

    public static void main(String[] args) {
        System.out.println(solution("()") == 0);
        System.out.println(solution("(((") == 3);
        System.out.println(solution("()") == 0);
        System.out.println(solution("()))((") == 4);
    }
}

四、时间和空间复杂度分析

时间复杂度分析

  1. 遍历字符串: 代码中通过 s.toCharArray() 将字符串转换为字符数组,然后用增强 for 循环遍历每个字符。这一部分的时间复杂度是 O(n),其中 n 是字符串的长度。

  2. 栈操作: 在循环中,栈的 pushpop 操作都是 O(1) 的,因此每次进行栈的操作都是常数时间。

    综合来看,整个算法的时间复杂度为 O(n)。

空间复杂度分析

  1. 栈空间: 在最坏情况下,所有字符都是左括号 (,那么栈的最大大小将达到 n。因此,栈的空间复杂度为 O(n)。

  2. 额外空间: 除了栈,算法只使用了一个 count 整数变量,额外空间复杂度是 O(1)。

    因此,整体的空间复杂度是 O(n)。

五、刷后感

这道题的难度相对较低,主要考察了对栈数据结构的理解和运用。在解决问题的过程中,我感受到了以下几点:

  1. 栈的直观性: 使用栈来处理括号匹配的问题非常自然。每当遇到一个左括号时,就将其入栈,遇到右括号时则尝试出栈,这种后进先出的特性恰好适合解决配对的问题。
  2. 边界情况处理: 在实现时,特别需要注意一些边界情况,比如字符串为空、全是左括号或全是右括号。这些情况都能通过简单的逻辑判断得到妥善处理。
  3. 时间与空间复杂度: 通过对时间和空间复杂度的分析,加深了对算法性能的理解。对于涉及到栈的问题,通常时间复杂度都是 O(n),而空间复杂度可能取决于最坏情况下的栈深度,这些都在此题中得到了验证。
  4. 复习基础知识: 这道题让我温习了栈的基本操作,以及在实际问题中应用数据结构的思维方式,增强了我的编程基础。

总的来说,这道题虽然不难,但却是巩固栈知识的一个很好的练习。