[路飞]_每天刷leetcode_21(删除最外层括号 Outermost Parentheses)

439 阅读2分钟

删除最外层括号

LeetCode传送门1021. Remove Outermost Parentheses

题目

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

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

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

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

A valid parentheses string is either empty "", "(" + A + ")", or A + B, where A and B are valid parentheses strings, and + represents string concatenation.

For example, "", "()", "(())()", and "(()(()))" are all valid parentheses strings. A valid parentheses string s is primitive if it is nonempty, and there does not exist a way to split it into s = A + B, with A and B nonempty valid parentheses strings.

Given a valid parentheses string s, consider its primitive decomposition: s = P1 + P2 + ... + Pk, where Pi are primitive valid parentheses strings.

Return s after removing the outermost parentheses of every primitive string in the primitive decomposition of s.

Example

Input: s = "(()())(())"
Output: "()()()"
Explanation: 
The input string is "(()())(())", with primitive decomposition "(()())" + "(())".
After removing outer parentheses of each part, this is "()()" + "()" = "()()()".

Input: s = "(()())(())(()(()))"
Output: "()()()()(())"
Explanation: 
The input string is "(()())(())(()(()))", with primitive decomposition "(()())" + "(())" + "(()(()))".
After removing outer parentheses of each part, this is "()()" + "()" + "()(())" = "()()()()(())".

Input: s = "()()"
Output: ""
Explanation: 
The input string is "()()", with primitive decomposition "()" + "()".
After removing outer parentheses of each part, this is "" + "" = "".

Constraints:

  • 1 <= s.length <= 10^5
  • s[i] is either '(' or ')'.
  • s is a valid parentheses string.

思考线


解题思路

​ // 循环s中的元素。设isDone = ture. counts = 0

​ // 如果 isDone = true, counts = 0, 表示为第一个字符。 isDone = false, counts +=1; temp = '';

​ // 遇到 '(' counts+=1; 遇到')' counts-=1, temp +=s[i] 若 counts = 0; 设置 isDone = true. 同时 s= s+temp; temp = '';

​ // 最后 return s`;

看到这道题我首先想到这又是一道关于stack的题目,题中的原语化分解其实可以分成对应的几个栈。但是如何实现代码我却一时没有头绪。

那我们先观察规律,看能不能不适用栈来解决呢?

首先我们观察某个原语化的部分,从字符串开始若连续()的部分一样多则说明这是一个整体部分。

要解决问题我们肯定要对s进行循环。在循环前 我们设置变量counts = 0来表示某个原语化部分是否完成闭环。遇到( counts ++; 遇到) counts --;

我们再设置 temp = ''来保存我们需要放入 结果res中的值。

在遍历的过程中

  • 如果 counts ===0则说明是个原语化的开始部分 执行 temp = ''; counts++;
  • 如果counts !==0;s[i] ==='(' ,说明是个增加部分,后面肯定有闭合括号要与之对应,且该值需要被记录下来。
  • 如果counts !==0; s[i] ===')',说明这个是闭合部分,我们要让``counts--且判断 此时 counts的值是否为0. 若counts ===0则需要把 temp放入到 结果res中 若 counts !==0则把s[i]`放入 temp中

有了以上思路那我们的代码就很好实现了。

/**
 * @param {string} s
 * @return {string}
 */
var removeOuterParentheses = function (s) {
    let isDone = true;
    let counts = 0;
    let temp = '';
    let res = '';
    for (let i = 0; i < s.length; i++) {
        if (counts === 0) {
            counts += 1;
            temp = ''
        } else if (s[i] === '(') {
            counts += 1;
            temp += s[i];

        } else if (s[i] === ')') {
            counts -= 1;
            if (counts === 0) {
                res += temp;
                temp = '';
            } else {
                temp += s[i]
            }
        }
    }
    return res;
};

那么我们能不能优化一下这段代码呢?其实是可以的。

其实我们只需要记录counts就可以。

如果s[i]==='(' 并且 counts >1,说明其满足放入结果的条件,或者如果s[i] === ')'并且counts > 0, 也说明其满足放入最后结果的条件。那么我们可以得到简化后的代码如下。

/**
 * @param {string} s
 * @return {string}
 */
var removeOuterParentheses = function (s) {
    let counts = 0;
    let res = '';
    for (let i = 0; i < s.length; i++) {
        if(s[i] === '(' && ++counts >1 || s[i] ===')' && --counts >0) res +=s[i];
    }
    return res;
};

那么我们最后再思考一下是否可以用stack的性质来解决问题呢? 经过最后的思考我发现,我们可以用栈来记录字符串的位置i, 每次遇到(把值推入,遇到)执行栈的推出。那么当栈为空的推出的stack.pop() +1就是我们要记录的当前原语的起始位置,而判断处的i-1就是我们当前原语的结束位置。 根据这个特性,我们可以得到以下代码:

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

        }
    }
    return res;
};

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。