在问 · 算法题解

1190. 反转每对括号间的子串

题目描述

输入字符串 s,只含小写英文字母和括号,括号保证两两配对。

从最内层的括号开始,逐层向外,把每对括号之间的内容整体反转。

返回处理完所有括号后的字符串,结果中不能留下任何括号。

示例 1
输入:s = "(abcd)"
输出:"dcba"

解释:把 abcd 反转。

示例 2
输入:s = "(u(love)i)"
输出:"iloveu"

解释:先反转 love 得到 evol,再反转整个 uevoli。

示例 3
输入:s = "(ed(et(oc))el)"
输出:"leetcode"

解释:依次反转 oc、etco,最后反转整串。

数据范围

  • 1 <= s.length <= 2000
  • s 只含小写英文字母和括号。
  • 保证所有括号都成对出现。

解题思路:栈模拟

括号嵌套就是栈的结构。栈中每一层是一个正在收集的字符列表,最底层是外面的结果。遇到 ( 就开一个新层;遇到字母就加到栈顶层;遇到 ) 说明当前层已经是一对括号内的完整内容(它更里面的括号已经处理好),把它弹出、反转,接到下面一层的末尾。

为什么正确

栈的层数 = 当前未闭合的左括号数 + 1;每层保存的是该括号内已经完成内层反转的内容。

复杂度分析

时间最坏 O(n^2)(每层弹出时要复制反转),n <= 2000 足够;空间 O(n)。

易错点

不要先处理最外层:反转必须从内到外。用栈时遇到 ) 弹出的一定是最内层,顺序自然正确。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def reverseParentheses(self, s: str) -> str:
        stack = [[]]
        for c in s:
            if c == '(':
                stack.append([])
            elif c == ')':
                inner = stack.pop()
                stack[-1].extend(reversed(inner))
            else:
                stack[-1].append(c)
        return ''.join(stack[0])

载入编辑器,自己跑一遍 →

其他解法

栈模拟每闭合一层括号就把内容反转一次,嵌套深时会反复翻转同一段字符,最坏 O(n²);配对跳转法通过改变读取方向代替真正的翻转,只扫描一遍。

解法 2:预处理括号配对 + 反向遍历 时间 O(n),空间 O(n)

先用栈求出每个括号对应的另一半的位置 pair。然后从左到右遍历,遇到普通字符就加入答案;遇到括号时跳到它配对的括号处,并把遍历方向反过来。这相当于进入一层括号时从另一端往回读,读完这层后再跳回来恢复原方向。每个字符恰好被访问一次。

不需要反复翻转字符串,严格线性时间,嵌套很深时优势明显。跳转加换向的正确性不太直观,需要手工模拟一遍才能理解。

class Solution:
    def reverseParentheses(self, s: str) -> str:
        n = len(s)
        pair = [0] * n
        stack = []
        for i, c in enumerate(s):
            if c == '(':
                stack.append(i)
            elif c == ')':
                j = stack.pop()
                pair[i], pair[j] = j, i
        res = []
        i, step = 0, 1
        while i < n:
            if s[i] in '()':
                i = pair[i]
                step = -step
            else:
                res.append(s[i])
            i += step
        return ''.join(res)

栈与堆 专题的其他题目

查看 栈与堆 全部题目 →