1399. 统计最大组的数目
1399. 统计最大组的数目
题目
You are given an integer n
.
Each number from 1
to n
is grouped according to the sum of its digits.
Return the number of groups that have the largest size.
Example 1:
Input: n = 13
Output: 4
Explanation: There are 9 groups in total, they are grouped according sum of its digits of numbers from 1 to 13:
[1,10], [2,11], [3,12], [4,13], [5], [6], [7], [8], [9].
There are 4 groups with largest size.
Example 2:
Input: n = 2
Output: 2
Explanation: There are 2 groups [1], [2] of size 1.
Constraints:
1 <= n <= 10^4
题目大意
给你一个整数 n
。请你先求出从 1
到 n
的每个整数 10 进制表示下的数位和(每一位上的数字相加),然后把数位和相等的数字放到同一个组中。
请你统计每个组中的数字数目,并返回数字数目并列最多的组有多少个。
示例 1:
输入: n = 13
输出: 4
解释: 总共有 9 个组,将 1 到 13 按数位求和后这些组分别是:
[1,10],[2,11],[3,12],[4,13],[5],[6],[7],[8],[9]。总共有 4 个组拥有的数字并列最多。
示例 2:
输入: n = 2
输出: 2
解释: 总共有 2 个大小为 1 的组 [1],[2]。
示例 3:
输入: n = 15
输出: 6
示例 4:
输入: n = 24
输出: 5
提示:
1 <= n <= 10^4
解题思路
理解数字和的计算
对于一个整数i
,其数字和可以通过计算所有位的和得到。例如,123
的数字和是1 + 2 + 3 = 6
。
我们可以通过动态规划(dp
表示数字和的缓存)快速计算i
的数字和:dp[i] = dp[Math.floor(i / 10)] + i % 10
- 即数字和等于去掉最后一位的数字和,加上最后一位。
- 可以看出需要缓存
dp
的最大值为Math.max(n / 10, 10)
统计数字和的频率
用一个数组count
来记录每个数字和的出现频率,其中索引表示数字和(从 1 开始)。
遍历从1
到n
的所有数字,计算每个数字的数字和,并更新对应的频率。计算最大组的数量
- 找到频率数组中最大的值
largest
。 - 统计频率等于
largest
的组数。
- 找到频率数组中最大的值
返回最大组的数量。
复杂度分析
- 时间复杂度:
O(n)
,- 遍历数字:从
1
到n
需要遍历一次,时间复杂度为O(n)
。 - 计算最大值和过滤:对
count
数组操作是常数级别的,时间复杂度为O(1)
(最多4 * 9 = 36
项)。
- 遍历数字:从
- 空间复杂度:
O(1)
,动态规划缓存dp
和频率数组count
的空间均为有限大小的常数级。
代码
/**
* @param {number} n
* @return {number}
*/
var countLargestGroup = function (n) {
let dp = { 0: 0 }; // 缓存数字和的动态规划表
const dpSize = Math.max(n / 10, 10); // 缓存大小的最大值
let count = new Array(4 * 9).fill(0); // 统计每个数字和的频率
for (let i = 1; i <= n; i++) {
const quotient = Math.floor(i / 10); // 十位
const reminder = i % 10; // 个位
const digitSum = reminder + dp[quotient]; // 当前数字的数字和
if (i <= dpSize) {
dp[i] = digitSum; // 更新动态规划缓存
}
count[digitSum - 1]++; // 更新数字和的频率
}
const largest = Math.max(...count); // 找到最大组大小
return count.filter((i) => i == largest).length; // 统计最大组的数量
};