Medium
题目描述
给你一个下标从 0 开始的整数数组 candies。数组中的每个元素表示大小为 candies[i] 的一堆糖果。你可以将每堆糖果分成任意数量的子堆,但 不能 将两堆糖果合并在一起。
同时给你一个整数 k。你需要将这些糖果堆分配给 k 个孩子,使得每个孩子都能获得 相同数量 的糖果。每个孩子可以分配到的糖果都来自于同一堆,并且有些糖果堆可能不会被使用。
返回每个孩子可以获得的 最大糖果数目 。
示例 1:
输入:candies = [5,8,6], k = 3
输出:5
解释:我们可以将 candies[1] 分成大小为 5 和 3 的两堆,将 candies[2] 分成大小为 5 和 1 的两堆。现在我们有五堆糖果,大小分别为 5、5、3、5 和 1 。我们可以把 3 堆大小为 5 的糖果分配给 3 个孩子。可以证明每个孩子无法获得超过 5 颗糖果。
示例 2:
输入:candies = [2,5], k = 11
输出:0
解释:总共有 11 个孩子,但只有 7 颗糖果,所以不可能保证每个孩子至少能获得一颗糖果。因此,每个孩子都得不到糖果,答案是 0 。
提示:
1 <= candies.length <= 10^51 <= candies[i] <= 10^71 <= k <= 10^12
解题思路
这是一个典型的二分搜索问题。关键在于理解题目要求:我们需要找到每个孩子能获得的最大糖果数量。
核心思路:
对于给定的糖果数量 x,我们可以检查是否能让 k 个孩子每人都获得 x 颗糖果:
- 遍历每堆糖果,计算每堆能提供多少个大小为
x的子堆(即candies[i] / x) - 如果总的子堆数量 ≥ k,则可以满足要求
二分搜索策略:
- 左边界:0(最坏情况下每个孩子得不到任何糖果)
- 右边界:糖果总数 / k(理论最大值)
- 对于中间值
mid,检查是否可行:- 如果可行,说明答案可能更大,在右半部分继续搜索
- 如果不可行,说明
mid太大,在左半部分搜索
这种方法的时间复杂度为 O(n × log(sum/k)),其中 n 是糖果堆的数量。空间复杂度为 O(1)。
推荐解法: 二分搜索是最优解法,既高效又容易理解。
代码实现
class Solution {
public:
int maximumCandies(vector<int>& candies, long long k) {
long long sum = 0;
for (int candy : candies) {
sum += candy;
}
long long left = 0, right = sum / k;
while (left < right) {
long long mid = left + (right - left + 1) / 2;
long long count = 0;
for (int candy : candies) {
count += candy / mid;
}
if (count >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
};
class Solution:
def maximumCandies(self, candies: List[int], k: int) -> int:
left, right = 0, sum(candies) // k
while left < right:
mid = (left + right + 1) // 2
count = sum(candy // mid for candy in candies)
if count >= k:
left = mid
else:
right = mid - 1
return left
public class Solution {
public int MaximumCandies(int[] candies, long k) {
long sum = 0;
foreach (int candy in candies) {
sum += candy;
}
long left = 0, right = sum / k;
while (left < right) {
long mid = left + (right - left + 1) / 2;
long count = 0;
foreach (int candy in candies) {
count += candy / mid;
}
if (count >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return (int)left;
}
}
var maximumCandies = function(candies, k) {
const sum = candies.reduce((acc, candy) => acc + candy, 0);
let left = 0, right = Math.floor(sum / k);
while (left < right) {
const mid = Math.floor((left + right + 1) / 2);
let count = 0;
for (const candy of candies) {
count += Math.floor(candy / mid);
}
if (count >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n × log(sum/k)) | n 为糖果堆数量,二分搜索范围为 [0, sum/k],每次检查需要遍历所有糖果堆 |
| 空间复杂度 | O(1) | 只使用常数额外空间 |
相关题目
. Koko Eating Bananas (Medium)
. Minimum Limit of Balls in a Bag (Medium)
. Minimum Speed to Arrive on Time (Medium)
. Minimized Maximum of Products Distributed to Any Store (Medium)
. Minimum Time to Complete Trips (Medium)
. Minimize Maximum of Array (Medium)