[leetCode 丶 20241114] 2117. 一个区间内所有数乘积的缩写

原题: 2117.一个区间内所有数乘积的缩写


描述:

给你两个正整数 leftright ,满足 left <= right 。请你计算 闭区间 [left, right] 中所有整数的 乘积

由于乘积可能非常大,你需要将它按照以下步骤 缩写

  1. 统计乘积中 后缀 0 的数目,并 移除 这些 0 ,将这个数目记为 C
  • 比方说,1000 中有 3 个后缀 0 ,546 中没有后缀 0 。
  1. 将乘积中剩余数字的位数记为 d 。如果 d > 10 ,那么将乘积表示为 <pre>...<suf> 的形式,其中 <pre> 表示乘积最 开始5 个数位, 表示删除后缀 0 之后 结尾的 5 个数位。如果 d <= 10 ,我们不对它做修改。
  • 比方说,我们将 1234567654321 表示为 12345...54321 ,但是 1234567 仍然表示为 1234567
  1. 最后,将乘积表示为 字符串 "<pre>...<suf>eC"
  • 比方说,12345678987600000 被表示为 "12345...89876e5"
    请你返回一个字符串,表示 闭区间 [left, right] 中所有整数 乘积缩写

示例 1

输入: left = 1, right = 4
输出: "24e0"
解释:
乘积为 1 × 2 × 3 × 4 = 24 。
由于没有后缀 0 ,所以 24 保持不变,缩写的结尾为 "e0" 。
因为乘积的结果是 2 位数,小于 10 ,所欲我们不进一步将它缩写。
所以,最终将乘积表示为 "24e0" 。

示例 2

输入: left = 2, right = 11
输出: "399168e2"
解释: 乘积为 39916800 。
有 2 个后缀 0 ,删除后得到 399168 。缩写的结尾为 "e2" 。
删除后缀 0 后是 6 位数,不需要进一步缩写。
所以,最终将乘积表示为 "399168e2" 。

示例 3

输入: left = 371, right = 375
输出: "7219856259e3"
解释: 乘积为 7219856259000 。

提示

  • 1 <= left <= right <= 10^4

个人版答案

执行用时: ... ms 执行内存消耗: ... M
力扣, 你玩不起, 你这个小垃圾

class Solution {
    public String abbreviateProduct(int left, int right) {
        long zero = 0,suf = 1, pre = 1, sufMax = 100_000_000_000L, preMax = 10_000_000_000_000_000L;
        boolean simple = true;
        for (int i = left; i <= right; i++){
            suf *= i;
            pre *= i;
            while (suf % 10 == 0){
                zero ++;
                suf /= 10;
            }
            if (suf > sufMax){
                simple = false;
                suf %= sufMax;
            }
            if (!simple){
                while (pre > preMax){
                    pre /= 10;
                }
            }
        }
        if (simple){
            return suf + "e" + zero;
        }
        return String.valueOf(pre).substring(0, 5) + "..." + String.valueOf(suf).substring(String.valueOf(suf).length() - 5) + "e" + zero;
    }
}

优秀解法

执行耗时: x ms

// 题目分析

个人解题思路与优秀答案解析

题目分析及个人版思路

  1. 一目十行. 这不是大数乘积的科学计数法么? 秒了
  2. 思路很简单, 如果小于十位, 只需要计算尾数0即可, 一直 / 10 直到不为0
  3. 然后如果超过十位, 那么只需要 % 十个0, 直到小于 100_000_000_000L.
  4. 前缀同理(我真的觉得同理啊~ 哈哈哈哈, 但是我忘记了丢失精度...我以为我用了long就很天才了.)
  5. 求前缀的一开始我使用的还是 sufMax. 100_000_000_000L. 然后简单用例过了, 百位数就GG.
  6. 所以我加了个0给preMax... 然后到千位. 结果遇见十位到千位的连续乘法就又凉了.. 然后我又加了个0...
  7. 好的, 我意识到自己计算方法中的前缀精度问题了...但是...不会啊
  8. 看题解...我看官方题解第一遍没看懂...准备再看的时候扫了眼评论区...然后...
  9. 力扣,你个小垃圾. 你玩不起...

进阶版思路
...看完我觉得我是正常人...
一个数据团灭绝大部分代码(包括标程):误差分析的一些知识,以及O(polylog n)的0ms做法