力扣(leetcode)每日一题 2390 从字符串中移除星号

题干

给你一个包含若干星号 * 的字符串 s 。

在一步操作中,你可以:

选中 s 中的一个星号。
移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。
返回移除 所有 星号之后的字符串。

注意:

生成的输入保证总是可以执行题面中描述的操作。
可以证明结果字符串是唯一的。

示例 1:

输入:s = “leet**cod*e”
输出:“lecoe”
解释:从左到右执行移除操作:

  • 距离第 1 个星号最近的字符是 “leet**code" 中的 ‘t’ ,s 变为 "leecod*e” 。
  • 距离第 2 个星号最近的字符是 “leecode” 中的 ‘e’ ,s 变为 “lecod*e” 。
  • 距离第 3 个星号最近的字符是 “lecod*e” 中的 ‘d’ ,s 变为 “lecoe” 。
    不存在其他星号,返回 “lecoe” 。
    示例 2:

输入:s = “erase*****”
输出:“”
解释:整个字符串都会被移除,所以返回空字符串。

题解

这里星号要抹去前面的文字,可以想到用栈,先入栈,当出现星号的时候弹出字符。

然后有了初始的版本
为什么这里没有用stack,因为最后append拼接的时候感觉LinkedList写法更加方便

  public String removeStars(String s) {
        char[] charArray = s.toCharArray();
        LinkedList<Character> list = new LinkedList<>();
        for (int i = 0; i < charArray.length; i++) {
            if (charArray[i] == '*') {
                if (!list.isEmpty()) {
                    list.pollLast();
                }
            } else {
                list.addLast(charArray[i]);
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            stringBuilder.append(list.get(i));
        }
        return stringBuilder.toString();
    }

然后时间没有过,感觉是因为LinkedList节点上不连续的原因
然后换了栈的方式,栈在java底层的实现是数组,有自动扩容的功能。
只所以这样写,还是因为不想最后拼接字符串的时候重复两次


   public String removeStars(String s) {
       // 指针来回跳吧
       char[] charArray = s.toCharArray();
       Stack<Character> stack = new Stack<>();
       int count = 0;
       for (int i = charArray.length - 1; i >= 0; i--) {
           if (charArray[i] == '*') {
               count++;
           } else if (count > 0) {
               count--;
           } else {
               stack.add(charArray[i]);
           }
       }
       StringBuilder stringBuilder = new StringBuilder();
       while (!stack.isEmpty()) {
           stringBuilder.append(stack.pop());
       }
       return stringBuilder.toString();
   }

但是跑出来的成绩还是不理想
这里官方的题解用了stringBuilder的setLength方法,还是第一次接触, 内部调用 Arrays.fill(value, count, newLength, ‘\0’);

    public String removeStars(String s) {
        StringBuilder res = new StringBuilder();
        for (char c : s.toCharArray()) {
            if (c != '*') {
                res.append(c);
            } else {
                res.setLength(res.length() - 1);   // 内部调用 Arrays.fill(value, count, newLength, '\0');  
            }
        }
        return res.toString();  //  内部调用  return new String(value, 0, count); 
    }

题外话:
Arrays.fill(array, startIndex, endIndex, value); 填充到指定范围位置

  • array:这是目标数组,您想要在其中填充元素。数组的元素类型必须与value的类型相匹配。
  • startIndex:这是要填充范围的起始索引,包括在内。这是填充操作的起始位置。
  • endIndex:这是要填充范围的结束索引,不包括在内。填充操作将一直持续到索引endIndex - 1。
  • value:这是要设置的值,它必须与数组元素的类型相匹配。在指定范围内的所有元素都将被设置为这个值。
    res.setLength(res.length() - 1); 这段代码的意思就是把数组的最后的位置的空格给设置了空
进一步优化:

这里不用stringBuilder,我们可以自己用数组来维护,因为stringbuilder的底层就是数组
然后可以减少一次遍历来拼接字符串

  public static String removeStars(String s) {
        int[] arr = new int[s.length()];
        int count = 0;
        for (char c : s.toCharArray()) {
            if (c != '*') {
                arr[count] = c;
                count++;
            } else if (count > 0) {
                count--;
            }
        }
        return new String(arr, 0, count);
    }


从38到了95
在这里插入图片描述

再进一步优化:

上面有两个数组,然后希望用一个数组实现,于是代码演化如下

 public static String removeStars(String s) {
    int count = 0;
      char[] charArray = s.toCharArray();
      for (int i = 0; i < charArray.length; i++) {
          if (charArray[i] != '*') {
              charArray[count] = charArray[i];
              count++;
          } else if (count > 0) {
              count--;
          }
      }
      return new String(charArray, 0, count);
    }

在这里插入图片描述

总结

官方的题解是很妙,但是还是要回归朴素的思维一步一步推到为妙

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值