LeetCode探索(76):1021-删除最外层的括号

123 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

题目

有效括号字符串为空 """(" + A + ")"A + B ,其中 AB 都是有效的括号字符串,+ 代表字符串的连接。

  • 例如,"""()""(())()""(()(()))" 都是有效的括号字符串。

如果有效字符串 s 非空,且不存在将其拆分为 s = A + B 的方法,我们称其为原语(primitive) ,其中 AB 都是非空有效括号字符串。

给出一个非空有效字符串 s,考虑将其进行原语化分解,使得:s = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。

s 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 s

示例 1:

输入:s = "(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。

示例 2:

输入:s = "(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。

示例 3:

输入:s = "()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""

提示:

  • 1 <= s.length <= 10^5
  • s[i]'('')'
  • s 是一个有效括号字符串

思考

本题难度简单。但是实际上没那么简单啊!

首先是读懂题意。有效的括号字符串有哪些呢?比如 "","()","(())()" 和 "(()(()))"。「原语」就是不能再拆分成两个有效括号字符串 A + B的字符串,比如字符串"()()",原语化分解得到 "()" + "()"。那么,我们接下来考虑如何解决这道题。

本题是括号匹配类型的题目,我们可以使用栈!遍历给出的字符串,当遇到"("时,入栈前,栈是空,说明 "(" 是原语字符串的最外层括号的开头,因此不放入 res中。当遇到 ")" 弹出栈顶以后,栈是空,说明 ")" 是原语字符串的最外层括号的结束,因此不放入 res中。因此,pop之后判断是否将当前字符加入res,push之前也要判断。

考虑到我们需要遍历一次字符串,因此时间复杂度是O(n),其中 n 为字符串的长度。下面是具体代码。

解答

方法一:栈

/**
 * @param {string} s
 * @return {string}
 */
var removeOuterParentheses = function(s) {
  let res = ''
  const stack = []
  for (let i = 0; i < s.length; i++) {
    let c = s[i]
    if (c === ')') {
      stack.pop()
    }
    if (stack.length) {
      res += c
    }
    if (c === '(') {
      stack.push(c)
    }
  }
  return res
}

// 执行用时:68 ms, 在所有 JavaScript 提交中击败了49.08%的用户
// 内存消耗:43.1 MB, 在所有 JavaScript 提交中击败了24.54%的用户
// 通过测试用例:59 / 59

复杂度分析:

  • 时间复杂度:O(n),其中 n 为字符串的长度。
  • 空间复杂度:O(n)。

参考