【LeetCode】1742.盒子中小球的最大数量

题目描述

你在一家生产小球的玩具厂工作,有 n 个小球,编号从 lowLimit 开始,到 highLimit 结束(包括 lowLimit 和 highLimit ,即 n == highLimit - lowLimit + 1)。另有无限数量的盒子,编号从 1 到 infinity 。
你的工作是将每个小球放入盒子中,其中盒子的编号应当等于小球编号上每位数字的和。例如,编号 321 的小球应当放入编号 3 + 2 + 1 = 6 的盒子,而编号 10 的小球应当放入编号 1 + 0 = 1 的盒子。
给你两个整数 lowLimit 和 highLimit ,返回放有最多小球的盒子中的小球数量。如果有多个盒子都满足放有最多小球,只需返回其中任一盒子的小球数量。

示例 1:

输入:lowLimit = 1, highLimit = 10
输出:2
解释:
盒子编号:1 2 3 4 5 6 7 8 9 10 11 …
小球数量:2 1 1 1 1 1 1 1 1 0 0 …
编号 1 的盒子放有最多小球,小球数量为 2 。

示例 2:

输入:lowLimit = 5, highLimit = 15
输出:2
解释:
盒子编号:1 2 3 4 5 6 7 8 9 10 11 …
小球数量:1 1 1 1 2 2 1 1 1 0 0 …
编号 5 和 6 的盒子放有最多小球,每个盒子中的小球数量都是 2 。

示例 3:

输入:lowLimit = 19, highLimit = 28
输出:2
解释:
盒子编号:1 2 3 4 5 6 7 8 9 10 11 12 …
小球数量:0 1 1 1 1 1 1 1 1 2 0 0 …
编号 10 的盒子放有最多小球,小球数量为 2 。

提示:

1 <= lowLimit <= highLimit <= 105

方法一:哈希表(暴力求解)

class Solution {
public:
    // 计算每个位置上的数字之和
    int SumPerNum(int i){
        int sum=0;
        while(i > 0){
            sum += i % 10;
            i /= 10;
        }
        return sum;
    }
    int countBalls(int lowLimit, int highLimit) {
        // 哈希表,空间换时间
        // 根据题目可知highlimit <= 99999 因此最大为45
        // 所以数组比45大就可以
        vector<int> boxes(46); 
        int maxBall=0;
        int n = highLimit - lowLimit + 1;
        for(int i=lowLimit; i<=highLimit; i++){
            int boxNum = SumPerNum(i);
            boxes[boxNum] ++;
            maxBall = max(maxBall, boxes[boxNum]);
        }
        return maxBall;
    }
};

方法二:找规律

class Solution {
public:
    int countBalls(int lowLimit, int highLimit) {
        vector<int> boxes(46);
        int maxNum=1;

        // 对于lowLimit首先处理
        int firstIndex=0, firstNum = lowLimit;        
        while(firstNum > 0){
            firstIndex += firstNum % 10;
            firstNum /= 10;
        }
        boxes[firstIndex] = 1;
        for(int i=lowLimit; i<highLimit; i++){
            // 对编号末尾为9的小球特殊处理
            // 9Index = firstIndex - n * 9 + 1 
            // 计算的是它的下一个球的箱子编号 
            int prevNum = i;
            while(prevNum % 10 == 9){
                firstIndex -= 9; // 前移9位
                prevNum /= 10;
            }
            boxes[++firstIndex] ++;
            maxNum = max(maxNum, boxes[firstIndex]);
        }
        return maxNum;
    }
};

心得

  • 这道题不难,一开始就能想到。

方法一:哈希表

  • 思路
    依次计算每个数字的各个位置的数的和,存入对应的哈希表,比较当前盒子里球的数量和已存放最多球的数量。
  • 误区
    • vector< int> boxes(数组长度),不用初始化,默认为0;
    • 此外,要学会看提示,比如这道题告诉了我们highLimit <= 105 ,因此当highLimit = 99999时,各个数之和达到最大,即45,因此数组只需要开到46即可,能有效减少内存。

方法二:找规律

  • 思路:
    • 当小球 A 的编号为 9 的时候,被放入箱子 9 ;小球 B 的编号为 10,会被放入箱子 1;
      当小球 A 的编号为 19 的时候,被放入箱子 10 ;小球 B 的编号为 20,会被放入箱子 2;
      当小球 A 的编号为 29 的时候,被放入箱子 11 ;小球 B 的编号为 30,会被放入箱子 3;

      当小球 A 的编号为 999 的时候,被放入箱子 27 ;小球 B 的编号为 1000,会被放入箱子 1;
      从上面可以看出,当小球 A 的编号末尾数只有一个 9 的时候,小球 B 会被放入 [ 小球A的箱子号 - 9 + 1 ]
      当小球 A 的编号末尾数有若干个 9 的时候,小球 B 会被放入 [ 小球A的箱子号 - n * 9 + 1 ]
      综上所述,当小球 A 的编号末尾数有若干个 9 的时候,小球 B 的箱子编号: [ 小球A的箱子号 - n * 9 + 1 ]
    • 对于编号末尾不是 9 的小球,它的下一个球的箱子号就是当前箱子号 + 1。
    • 因此,只需要对末尾数字为 9 的小球进行特殊计算即可。
  • 误区:
    • 在计算lowLimit的各位数字之和的时候,应该先保存lowLimit,否则在从 lowLimit -> highLimit 的总循环中就会出错;
    • 在总循环里面,我们都是通过上一个小球得到下一个小球,因此要记住 boxes[++ firstIndex] ++ ,firstIndex要自加;

你可能感兴趣的:(LeetCode刷题,leetcode,算法,职场和发展)