有效括号字符串为空"""("+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 <= 105
  • s[i]'('')'
  • s 是一个有效括号字符串

计数:

从 ss 开始位置计算子数组的和,遇到 ‘(’ 则加 1,遇到‘)’ 则减 1,第一次和为 0 时则为第一个原语。从上一个原语的结束位置的下一个位置开始继续求子数组的和,和首次为 0 时则是另一个新的原语,直到遇到 s 的结尾。保存结果时,忽略每个原语的开始字符和结尾字符,其他字符均保存下来生成新的字符串。代码对流程进行了部分优化,减少了判断语句。

  1. class Solution {
  2. public String removeOuterParentheses(String S) {
  3. StringBuilder sb = new StringBuilder();
  4. int level = 0;
  5. for (char c : S.toCharArray()) {
  6. if (c == ')') --level;
  7. if (level >= 1) sb.append(c);
  8. if (c == '(') ++level;
  9. }
  10. return sb.toString();
  11. }
  12. }

栈:

遍历 s,并用一个栈来表示括号的深度。遇到‘(’ 则将字符入栈,遇到‘)’ 则将栈顶字符出栈。栈从空到下一次空的过程,则是扫描了一个原语的过程。一个原语中,首字符和尾字符应该舍去,其他字符需放入结果字符串中。因此,在遇到 ‘(’ 并将字符入栈后,如果栈的深度为 1,则不把字符放入结果;在遇到‘)’ 并将栈顶字符出栈后,如果栈为空,则不把字符放入结果。其他情况下,需要把字符放入结果。代码对流程进行了部分优化,减少了判断语句。

  1. class Solution {
  2. public String removeOuterParentheses(String s) {
  3. StringBuilder res = new StringBuilder();
  4. Deque<Character> stack = new ArrayDeque<>();
  5. for (char c : s.toCharArray()) {
  6. if (c == ')') stack.pop();
  7. if (!stack.isEmpty()) res.append(c);
  8. if (c == '(') stack.push(c);
  9. }
  10. return res.toString();
  11. }
  12. }