03删除最外层括号1021

03删除最外层括号1021

1.Comprehend 理解题意

给出一个非空有效字符串S,考虑将其进行原语化分解。 使得:S=P_1+P_2+…+P_k,其中P_i是有效括号字符串原语。 对S进行原语化分解,删除分解中每个原语字符串的最外层括号,返回S。

➢ 有效括号字符串:例如:“( )”,“( ( ) ) ( )” 和 “( ( ) ( ( ) ) )”

➢ 原语:如果有效字符串S非空,且不能将其拆分为 S =A+B,我们称其为原语(primitive), 其中A和B都是非空有效括号字符串。

题目基本信息

  • 有效括号字符串:括号必然成对出现
  • 给定字符串 S 非空,但返回结果可能为空
  • 原语化分解只需要进行一级
  • 返回删除每个原语的最外层括号后的字符串

附加信息

  • S.length <= 10000
  • S[i]为"(“或”)"

解法一:暴力解法

  • 先分解成字符串原语
  • 再删除每部分最外层括号
  • 返回各部分合并后的结果

解法二:优化解法

  • 对原字符串进行原语识别
  • 获取不包含最外层括号的子串
  • 将各部分拼接返回

2.Choose 数据结构及算法思维选择

解法一:分解、删除再合并

  • 数据结构:字符串、数组
  • 算法思维:遍历、计数器、累加

解法一:暴力解法思路分析

  1. 定义容器存储原语子串 new ArrayList();
  2. 定义左括号、右括号计数器: int left = 0, right = 0;
  3. 遍历字符串,读取到括号时对应计数器自增
  4. 检查是否到达原语结尾,截取原语子串并添加 到容器中
  5. 遍历容器,删除最外层括号后合并成新串

解法一:边界和细节问题

  1. 边界问题:

遍历字符串,注意索引越界:i < S.length() 截取原语字符串时,注意起止索引:[start, end)

  1. 细节问题:

需要记录上一次截取原语子串之后的位置 删除原语子串的最外层括号,其实就是重新截取

解法一:代码

  class Solution {
    
    
      public String removeOuterParentheses(String s) {
    
    
          char[] chars = s.toCharArray();
          int length = chars.length;
          int leftCount = 0, rightCount = 0, primitiveStart = 0;
          List<String> primitives = new ArrayList<>();
          for (int i = 0; i < length; i++) {
    
    
              char aChar = chars[i];
              if (aChar == '(') {
    
    
                  leftCount++;
              } else if (aChar == ')') {
    
    
                  rightCount++;
              }
              if (leftCount == rightCount) {
    
    
                  primitives.add(s.substring(primitiveStart, i + 1));
                  primitiveStart = i + 1;
              }
          }
          StringBuilder result = new StringBuilder();
          for (String primitive : primitives) {
    
    
              result.append(primitive.substring(1,primitive.length()-1));
          }
          return result.toString();
      }
  }

解法二:优化解法思路分析

  1. 定义容器存储删除外层括号后的原语子串 new StringBuilder();
  2. 定义左括号、右括号计数器: int left = 0, right = 0;
  3. 遍历字符串,读取到括号时对应计数器自增
  4. 检查是否到达原语结尾,截取不包含最外层的 原语子串并拼接到容器中

解法二代码

class Solution {
    
    
    public String removeOuterParentheses(String s) {
    
    
        char[] chars = s.toCharArray();
        int length = chars.length;
        StringBuilder result = new StringBuilder();
        int leftCount = 0, rightCount = 0, primitiveStart = 0;
        for (int i = 0; i < length; i++) {
    
    
            char aChar = chars[i];
            if (aChar == '(') {
    
    
                leftCount++;
            } else /*if (aChar == ')')*/ {
    
    
                rightCount++;
            }
            if (leftCount == rightCount) {
    
    
                result.append(s.substring(primitiveStart + 1, i));
                primitiveStart = i + 1;
            }
        }
        return result.toString();
    }
}

4.Consider 思考更优解

  1. 剔除无效代码或优化空间消耗
  • 只需要一个计数器:"(“自增,”)"自减
  • 如果字符串数据只是两两配对怎么处理?
  • 有没有一种支持后进先出的数据结构?
  1. 寻找更好的算法思维 • 借鉴其它算法

关键知识点:栈(Stack)

  • 限定仅在表尾进行插入和删除操作的线性表
  • 栈顶(Top):操作数据的一端,即表尾
  • 栈底(Bottom):线性表的另一端,即表头
  • 特点:LIFO(Last In First Out),后进先出
  • 基本操作:
    • 进栈:push(),在栈顶插入元素,入栈、压栈 • 出栈:pop(),从栈顶删除数据
    • 判断空:isEmpty()

在这里插入图片描述

5.Code 最优解思路及编码实现

最优解:栈解法

  1. 使用数组模拟一个栈,临时存储字符,替代计数器

    • push(Character) ; pop(); isEmpty()
  2. 遍历字符串,根据情况进行入栈/出栈操作

    • 读取到左括号,左括号入栈
    • 读取到右括号,左括号出栈
  3. 判断栈是否为空,若为空,找到了一个完整的原语

  4. 截取不含最外层括号的原语子串并进行拼接

最优解:边界和细节问题

  1. 边界问题:

遍历字符串,注意索引越界:i < S.length() 截取原语字符串时,注意起止索引:[start, end)

  1. 细节问题:

需要记录上一次截取原语子串之后的位置 右括号无需进栈

最优解代码

class Solution {
    
    
    public String removeOuterParentheses(String s) {
    
    
        StringBuilder result = new StringBuilder();
        char[] chars = s.toCharArray();
        int length = chars.length;
        int stackCount = 0;
        for (int i = 0; i < length; i++) {
    
    
            char aChar = chars[i];
            if (aChar == '(') {
    
    
                stackCount++;
                if (stackCount > 1) {
    
    
                    result.append(aChar);
                }
            } else {
    
    //aChar = ')'
                stackCount--;
                if (stackCount > 0) {
    
    
                    result.append(aChar);
                }
            }
        }
        return result.toString();
    }
}

6.Change 变形延伸

题目变形

  • (练习)删除最内层的括号
  • (练习)用链表实现一个栈(链栈)

延伸扩展

  • 逆波兰表达式求值:给定数字和运算符,根据规则计算出结果
  • 子程序调用:方法依次进栈,最后调用的最先结束

猜你喜欢

转载自blog.csdn.net/sinat_26394043/article/details/133174278
今日推荐