问题描述
粮食公司需要将nn吨粮食分配给若干分销商,每个分销商能够获得的粮食数量等于将nn除以分销商数量,向下取整。问题是,计算在可能的分销商数量中,分销商获得的不同粮食数量有多少种可能。
例如,如果粮食总量为5吨,当分销商数量为1时,分销商获得5吨;当分销商数量为2时,分销商获得2吨;当分销商数量为3、4、5时,分销商获得的粮食依次为1吨。这样,不同的分配方案有3种可能。
测试样例
样例1:
输入:
n = 5
输出:3
样例2:
输入:
n = 7
输出:4
样例3:
输入:
n = 10
输出:5
问题分析
题目要求我们计算粮食总量 n 被分配给不同数量的分销商时,分销商获得的粮食数量的不同种类数。每个分销商获得的粮食数量是 n // k,其中 k 是分销商的数量,n // k 表示整除操作。
关键点
- 对于一个给定的
n,我们可以考虑分销商的数量k从1到n逐个试探。对于每个k,分销商每人分得的粮食数量是n // k。 - 我们需要找出所有不同的
n // k的值的个数,即有多少种不同的粮食分配方式。
解题思路
-
观察商的规律:对于一个固定的
n,随着k的增大,n // k的值逐渐减小并趋于 0。每个商的值会有一段区间内是相同的。例如:- 对于
n = 10,n // 1 = 10,n // 2 = 5,n // 3 = 3,n // 4 = 2,n // 5 = 2,n // 6 = 1,... - 在商为
2时,k从4到5都是2,在商为1时,k从6到10都是1。
- 对于
-
优化思路:
- 我们可以通过计算每个商的值的区间来减少不必要的计算。例如,对于
n // k相同的区间,可以一次性处理。
- 我们可以通过计算每个商的值的区间来减少不必要的计算。例如,对于
-
算法步骤:
- 从
k = 1到k = n遍历。 - 记录
n // k的不同值。
- 从
-
使用集合去重:由于
n // k的值可能会重复,使用集合可以去掉重复的商值。
解释
- 思路:我们通过遍历从
1到n的每个k来计算n // k,并将结果存入一个集合unique_values。集合天然去重,因此相同的商值只会存储一次。 - 返回结果:集合的大小就是不同的粮食分配数量的种类数。
优化思路
虽然上述方法已经正确计算了结果,但其时间复杂度为 O(n),其中我们计算了每个 n // k 值。在某些情况下,这个过程可能可以通过更精确的分析和优化来减少计算的次数。
例如,我们可以发现:
- 当
n // k = x时,所有满足条件的k都在一定的区间内,因此我们可以跳过一些冗余的k值,直接将这些区间的商值加入集合中。
不过在大多数情况下,直接通过遍历所有 k 的方法也能得到正确且高效的结果。
时间复杂度
- 上述代码的时间复杂度为
O(n),因为我们对每个k(从1到n)都进行了计算。虽然存在优化空间,但一般来说,对于中等规模的n,这种方式已经足够高效。
示例说明
-
样例1:
- 输入:
n = 5 - 分销商数量可能是
1, 2, 3, 4, 5。 - 对应的
n // k分别是5, 2, 1, 1, 1。 - 不同的粮食数量有
3种:5, 2, 1。 - 输出:
3。
- 输入:
-
样例2:
- 输入:
n = 7 - 分销商数量可能是
1, 2, 3, 4, 5, 6, 7。 - 对应的
n // k分别是7, 3, 2, 1, 1, 1, 1。 - 不同的粮食数量有
4种:7, 3, 2, 1。 - 输出:
4。
- 输入:
-
样例3:
- 输入:
n = 10 - 分销商数量可能是
1, 2, 3, 4, 5, 6, 7, 8, 9, 10。 - 对应的
n // k分别是10, 5, 3, 2, 2, 1, 1, 1, 1, 1。 - 不同的粮食数量有
5种:10, 5, 3, 2, 1。 - 输出:
5。
- 输入:
def solution(n):
# 使用一个集合来记录不同的粮食分配量
unique_values = set()
# 遍历从1到n的每个分销商数量k
for k in range(1, n + 1):
unique_values.add(n // k)
# 返回不同分配量的数量
return len(unique_values)
# 测试样例
print(solution(5)) # 输出: 3
print(solution(7)) # 输出: 4
print(solution(10)) # 输出: 5