0
点赞
收藏
分享

微信扫一扫

【LeetCode】2288. 价格减免

一、题目描述

句子 是由若干个单词组成的字符串,单词之间用单个空格分隔,其中每个单词可以包含数字、小写字母、和美元符号 '$' 。如果单词的形式为美元符号后跟着一个非负实数,那么这个单词就表示一个价格。

  • 例如 "$100""$23""$6.75" 表示价格,而 "100""$""2$3" 不是。

注意: 本题输入中的价格均为整数。

给你一个字符串 sentence 和一个整数 discount 。对于每个表示价格的单词,都在价格的基础上减免 discount% ,并 更新 该单词到句子中。所有更新后的价格应该表示为一个 恰好保留小数点后两位 的数字。

返回表示修改后句子的字符串。

示例 1:

输入:sentence = "there are $1 $2 and 5$ candies in the shop", discount = 50
输出:"there are $0.50 $1.00 and 5$ candies in the shop"
解释:
表示价格的单词是 "$1" 和 "$2" 。 
- "$1" 减免 50% 为 "$0.50" ,所以 "$1" 替换为 "$0.50" 。
- "$2" 减免 50% 为 "$1" ,所以 "$1" 替换为 "$1.00" 。

示例 2:

输入:sentence = "1 2 $3 4 $5 $6 7 8$ $9 $10$", discount = 100
输出:"1 2 $0.00 4 $0.00 $0.00 7 8$ $0.00 $10$"
解释:
任何价格减免 100% 都会得到 0 。
表示价格的单词分别是 "$3"、"$5"、"$6" 和 "$9"。
每个单词都替换为 "$0.00"。

提示:

  • 1 <= sentence.length <= 105
  • sentence 由小写英文字母、数字、' ''$' 组成
  • sentence 不含前导和尾随空格
  • sentence 的所有单词都用单个空格分隔
  • 所有价格都是 整数且不含前导零
  • 所有价格 最多10 位数字
  • 0 <= discount <= 100

二、思路分析

拿到这道题的时候,可以看出来,只是替换题目中的数字,做起来并不难,但是看通过次数会发现通过率并不高。

首先从题目信息我们可以发现,题目中的数字都是整数,但是因为涉及到除法的操作,那么就出现精度的问题,这也是这个题中容易出现的坑。在Java中我们可以使用BigDecimal类做乘法和除法操作,避免出现精度丢失。

接着我们分析解题步骤:

  1. 先把句子按照空格做分割,存放字符串数组中
  2. 遍历字符串数组,判断字符串是否是$的开头的,如果是跳转到3,如果不是跳转到4
  3. 如果是$开头的字符串,开始遍历$后面的字符,一边遍历一边添加到数字字符串中。如果遍历过程中发现非数字字符,可以直接把整个字符返回。如果遍历到最后发现都是数字,则把整个数字字符串转化成BigDecimal类,做加减乘除的计算。把计算后的结果转化成字符串添加到结果字符串中。
  4. 如果不是$开头的字符串,直接把整个字符串添加到结果字符串中
  5. 字符串数组中的字符串遍历完以后,相当于整个字符串遍历结束。

这里有一个需要注意点,如果是单个$的长度,按照第3步的处理过程,因为后面没有数字,就相当于空串转BigDecimal类,会出错的。所以还需要判断字符串的长度哦。

示例代码

import java.math.BigDecimal;
import java.math.RoundingMode;

class Solution {
    public String discountPrices(String sentence, int discount) {
        // 根据空格分割字符串
        String[] arr = sentence.split(" ");
        StringBuilder sb = new StringBuilder();
        for (String str : arr) {
            // 如果是$开头的,并且字符串长度大于1,则判断是否需要做折扣计算
            if (str.startsWith("$") && str.length() > 1) {
                sb.append(processStr(str, discount));
            } else {
                sb.append(str);
            }
            sb.append(" ");
        }
        // 删除最后一个空格
        return sb.deleteCharAt(sb.length() - 1).toString();
    }

    public String processStr(String str, int discount) {
        // 计算后的字符串
        String result = "$";
        StringBuilder num = new StringBuilder();
        for (int i = 1; i < str.length(); i++) {
            char c = str.charAt(i);
            // 判断字符是否为数字
            if (c >= 48 && c <= 57) {
                num.append(c);
            } else {
                // 如果不是数字,可以直接把字符串返回
                return str;
            }
        }
        // 使用BigDecimal做高精度的计算
        BigDecimal bigDecimal = new BigDecimal(num.toString());
        return result + bigDecimal.subtract(bigDecimal.multiply(new BigDecimal(discount).divide(new BigDecimal(100))))
            .setScale(2, RoundingMode.HALF_UP);
    }
}

那么是不是还有其他的解法呢?

还有一些想法,尚未实现代码,感觉实现逻辑比较复杂。通过遍历字符串的每个字符,如果遇到$字符,则开始处理后面的数组字符,到遇到空格前,是否全部为数字。如果遇到非数字,则不用做计算了,如果全部是数字则需要做计算。

如果一个连续字符串中有多个$,比如123 $21$234$23,要注意处理最后的$23,防止把23做了更新操作。

相比于第一种方法,这里需要对所有的字符做处理,第一种解法中,通过分割字符串,跳过了很多不能转化的字符,但是需要额外的空间消耗。

三、总结

1、在代码中牵扯到乘法和除法操作的,涉及到小数部分的,都需要考虑到精度的问题。

2、在处理字符串的时候还需要考虑特殊的场景,比如开头或者结尾的部分出现一些标志性的数字或者字符,这时候该如何处理?

【LeetCode】2288. 价格减免_字符串

举报

相关推荐

0 条评论