[路飞]_今夜移除无效括号

434 阅读2分钟

移除无效的括号

题目

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

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

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

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

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

示例

输入:s = "lee(t(c)o)de)"
输出:"lee(t(c)o)de"
解释:"lee(t(co)de)" , "lee(t(c)ode)" 也是一个可行答案。

当时我做题时想的思路

忽略字母:

假设字符串有: s = "(())(()"

观察

0123456
(())())

明显可以看出第3位,多了一个"("右括号;

我第一次枚举记录无效的括号下标,再二次枚举的时候忽略这些无效的括号下标不就可以得到答案了?

怎么讲这个位置记录下来呢?

首先想到有效括号时成对出现的,只有右括号碰到左括号才能组成有效括号;思路来了;

用数组list将无效左括号下标保存,用rightList数组保存无效的右括号下标;保存规则如下:

  • 当遇到左括号【"("】;将下标放入数组,因为如果没有右括号,当前这个做括号是无效的;
  • 当遇到右括号,分类讨论:
    • 如果list数组为空,也就是说之前没有(;将当前坐标放在rightList
    • 如果list数组不为空,将list最后一位移除,因为当前右括号与list数组中左括号组成有效括号
  • 枚举完成,得到list和rightList为无效左右括号下标;
  • 在枚举一次,忽略list和rightList数组中下标的字符串;即可得到答案

代码

var minRemoveToMakeValid = function(s) {
    let len = s.length;
    let list = [];
    let leftlist = [];
    let str = ''
    for(let i = 0 ; i < len ; i++){
        if(s[i] === '('){
          list.push(i)
        }else if(s[i] === ')'){
           if(list.length === 0){
               leftlist.push(i)
           }else{
               list.pop();
           }
        }
    }
    const limit = leftlist.concat(list)
    for(let i = 0 ; i < len ; i++){
        if(!limit.includes(i))str+=s[i]
    }
    return str

};

优化后

按照自己的思路虽然也能AC,但是不但使用了额外空间,还使用了两个数组;优化一下;

怎么优化?

考虑优化点,枚举是没办法优化了,只能看看数组能不能不用了。

能不用数组记录无效括号数据吗?

在观察 s = "(())(()"

0123456
(())())

第一遍枚举的时候其实可以删除第4位上的( 左括号;

再观察 s = "))))(()"

0123456
))((())

第一遍枚举可以将所有无效的( 左括号删除,但是不能确定无效的右括号

这思路不就来了吗。

第一遍枚举从左到右删除无效左括号,

第二遍枚举从右到左删除无效右括号不就行了。

举个例子

假设 s = "))))(()" num = 0; num用于记录左括号数量,

下标0123456
字符串))((())
num0012321
  • 当num为0时遇到右括号,忽略
  • 当num大于0;遇到右括号,将右括号保存到新字符串中,num-1; 枚举结束后得到新字符串
下标01234
字符串((())
num12321

观察新字符串,此时num=1;

新字符串左括号正好多出来了1个;

新字符串从右到左枚举,遇到的num个左括号,忽略;

下标01234
字符串((())

然后得到:

下标0123
字符串(())

哈哈,搞定

代码

var minRemoveToMakeValid = function(s) {
    let len = s.length;
    let str = ''
    let num = 0;
    for(let i = 0 ; i < len ; i++){
        if(s[i] === '('){
          num++;
          str+=s[i]
        }else if(s[i] === ')'){
           if(num === 0){
           }else{
                str+=s[i];
                num--;
           }
        }else{
            str+=s[i]; 
        }
    }
    if(num === 0) return str;
    let result = ''
    for(let i =  str.length-1 ;i>=0 ; i--){
        if(str[i] === '(' && num > 0){
            num--;
            continue
        }
        result =   str[i] + result 
    }
    return result

};