[路飞]移除无效的括号

212 阅读2分钟

题目描述

给你一个由 '('、')' 和小写字母组成的字符串 s。

你需要从字符串中删除最少数目的 '(' 或者 ')' (可以删除任意位置的括号),使得剩下的「括号字符串」有效。

请返回任意一个合法字符串。

有效「括号字符串」应当符合以下 任意一条 要求:

空字符串或只包含小写字母的字符串 可以被写作 AB(A 连接 B)的字符串,其中 A 和 B 都是有效「括号字符串」 可以被写作 (A) 的字符串,其中 A 是一个有效的「括号字符串」

分析

输入: String, 让我们检查里面的括号可否全部闭合,如果不是那么去掉最少的括号
输出: String, 处理完成的字符串,里面没有括号或者括号均可闭合

解题思路

本题我们用一种不需要栈的方法,两次遍历这个字符串,首先去掉多余的右括号,再去掉多余的左括号,最后返回字符串。

第一轮:

声明一个计数器 cnt,表示左括号的个数,最后用来表示需要删多少个右括号,
声明一个空字符串 str,保存遍历到的所有合法的字符 然后遍历字符串,对当前字符分类讨论:

  • (, 计数器加一,把左括号放入 str
  • ), 如果当前计数器是 0,说明这个右括号不合法,我们需要舍弃他,否则合法,放入 str
  • 其他,放入 str

这一轮,我们删除了没用的右括号。

第二轮与第一轮是一样的,只不过要删除的是没用的左括号~

最终,我们要返回的是第二轮的结果。

代码

/**
 * @param {string} s
 * @return {string}
 */
var minRemoveToMakeValid = function (s) {
  let str = ""
  let cnt = 0
  for (let i = 0; i < s.length; i++) {
    if (s[i] === "(") {
      str += s[i]
      cnt++
    } else if (s[i] !== ")") {
      str += s[i]
    } else {
      if (!cnt) continue
      cnt--
      str += s[i]
    }
  }

  let ret = ""
  let cnt2 = 0
  for (let i = str.length - 1; i >= 0; i--) {
    if (str[i] === ")") {
      ret = ")" + ret
      cnt2++
    } else if (str[i] !== "(") {
      ret = str[i] + ret
    } else {
      if (!cnt2) continue
      cnt2--
      ret = "(" + ret
    }
  }

  return ret
}

复杂度

时间:O(N),字符串需要遍历两遍。
空间:O(N),存储的字符串最坏基本等于入参 s