258括号字符串最短长度计算 中等 | 豆包MarsCode AI刷题

6 阅读4分钟

括号字符串最短长度计算 | 豆包MarsCode AI刷题

这道题考察了我们对栈的运用,以及如何在栈的操作中最小化字符串的长度。题目中的括号字符串只包含 '('')',我们可以通过将相邻的括号对 () 进行合并操作,从而减小字符串的长度。这道题属于字符串处理和栈操作的综合问题,下面我们来详细分析题意、解题思路以及代码实现的关键点。

题目分析

题目给定了一串只包含 '('')' 的括号字符串。我们有两种操作选择:

  1. 将相邻的一对括号 '()' 合并成 '('
  2. 将相邻的一对括号 '()' 合并成 ')'

经过若干次操作后,我们希望将字符串缩短到最小长度,并求出最小长度是多少。

解题思路

由于我们可以选择将 '()' 转换成 '('')',这意味着我们可以“消掉”一对括号。如果我们仔细观察,可以发现,对于每一个'()',我们可以在缩短过程中将其转换为单个字符,最终目标是让字符串变成最短的可能形式。

关键思路

在这个问题中,栈是一种非常适合的工具,因为栈本身是“后进先出”的结构,能够帮助我们很方便地处理括号的配对关系。

我们可以通过栈的压栈和出栈操作来判断:

  1. 当前括号是否可以和栈顶元素形成配对并消掉。
  2. 如果无法消掉,就需要压栈以供后续的括号判断。

操作规则

对于栈的操作,我们主要分两种情况来处理:

  1. 如果当前字符是 '(',我们直接将它压入栈中。

  2. 如果当前字符是 ')',我们需要判断栈顶的情况:

    • 如果栈顶元素是 '(',那么我们找到了一对配对的括号 '()',可以进行“消除”操作。这里的“消除”指的是将栈顶的 '(' 出栈,然后将其合并成一个特殊字符 '?' 放回栈中,用于标记当前已配对的括号对。
    • 如果栈顶元素是 '?',说明前面已经合并过一个括号对,我们可以再次弹出栈顶的 '?',并继续保持当前的平衡。

经过多轮操作后,栈中剩下的字符数即为最终的最短长度。

核心代码解析

以下是完整的代码实现:

public static int solution(String s) {
    char[] arr = s.toCharArray();
    Stack<Character> st = new Stack<>();
    
    for (char c : arr) {
        if (c == '(') {
            // 遇到'('直接入栈
            st.push(c);
        } else {
            // 遇到')'时进行配对消除判断
            if (!st.isEmpty() && (st.peek() == '(' || st.peek() == '?')) {
                st.pop(); // 移除栈顶的'('或'?',表示消除
                
                // 进一步合并,确保只保留一个'?'作为当前的消除标记
                while (!st.isEmpty() && (st.peek() == '(' || st.peek() == '?')) {
                    st.pop();  
                }
                // 将合并后的标记符号'?'重新压栈
                st.push('?');
            } else {
                // 如果无法消除,直接将')'压栈
                st.push(c);
            }
        }
    }
    return st.size();
}

代码详解

  1. 初始化和遍历

    • 将字符串 s 转换为字符数组 arr,方便逐个字符处理。
    • 初始化一个空栈 st,用于存储未消除的括号。
  2. 入栈操作

    • 遍历字符数组 arr,当遇到 '(' 时,直接将其压入栈中。
  3. 配对消除

    • 当遇到 ')' 时,先检查栈顶元素。

      • 如果栈顶是 '(''?',说明当前 ')' 可以和栈顶配对消除。
      • 移除栈顶的 '(''?' 后,将 ')' 变为 '?' 标记当前已配对的状态。
    • 通过 while 循环进一步合并多余的 ? 标记,确保栈中只保留一个 '?'

  4. 最终结果

    • 遍历完字符串后,栈中的字符数量即为最短长度,因为所有能够消除的括号对都已消除。

栈操作过程示例

假设输入字符串为 "((()))()",我们分析其栈的变化过程:

  1. 初始栈为空。

  2. 遍历字符串:

    • '(' 入栈 → 栈内容:['(']
    • '(' 入栈 → 栈内容:['(', '(']
    • '(' 入栈 → 栈内容:['(', '(', '(']
    • ')' 遇到栈顶为 '(',弹出 → 栈内容:['(', '(']
    • ')' 遇到栈顶为 '(',弹出 → 栈内容:['(']
    • ')' 遇到栈顶为 '(',弹出 → 栈内容:[]
    • '(' 入栈 → 栈内容:['(']
    • ')' 遇到栈顶为 '(',弹出 → 栈内容:[]

最终栈为空,因此最短长度为 0,即所有括号对都能完全配对消除。

时间和空间复杂度分析

  • 时间复杂度:遍历字符串一次,每个字符进行常数时间操作,因此时间复杂度为 O(n)
  • 空间复杂度:最坏情况下,栈中存储所有括号,因此空间复杂度为 O(n)

边界情况分析

  1. 空字符串:返回 0
  2. 没有配对的括号:如 "((((""))))",返回栈中的字符数量,因为没有配对情况。
  3. 完全配对的括号:如 "()()",最终栈会为空,返回 0