You are given an array candies
where candies[i]
represents the number of candies in the i
-th pile. You are also given an integer k
representing the number of children.
Your task is to distribute the candies among k
children such that:
k
children, return 0.
In other words, you want to find the maximum integer x
such that you can allocate x
candies to each of k
children, by splitting the piles as needed, but not combining them.
Constraints:
1 <= candies.length <= 10^5
1 <= candies[i] <= 10^7
1 <= k <= 10^12
At first glance, you might think to try every possible number of candies per child, from the maximum pile size down to 1, and check if it's possible to allocate that many candies to each child. However, with constraints as large as 10^12
for k
, and piles up to 10^5
, this naive approach would be far too slow.
Instead, it's important to realize that this is an optimization problem: for a given number of candies per child, we can check whether it's possible to satisfy all k
children. If so, maybe we can do even better; if not, we need to try less. This pattern is perfect for binary search.
The key insight is to use binary search on the answer, i.e., the maximum number of candies per child, and efficiently check for each candidate value whether it's possible to allocate that many candies to all k
children.
Let's break down the steps for an efficient solution:
x
, we need to check if we can give x
candies to each of k
children.pile // x
children happy from that pile (since we can split but not combine piles).k
, then x
is feasible.x
is feasible, try a higher value (move the lower bound up).This approach is efficient because it reduces the search space logarithmically and checks feasibility in linear time per iteration.
Let's take an example:
candies = [5, 8, 6]
, k = 3
mid = (1 + 8) // 2 = 4
mid = (5 + 8) // 2 = 6
mid = (5 + 5) // 2 = 5
mid = (6 + 5) // 2 = 5
(already checked; binary search ends).The problem asks us to maximize the number of candies each child gets, given the ability to split piles but not combine them. The key insight is to use binary search on the answer, checking for each candidate value if it's feasible to satisfy all children. This results in a highly efficient solution that works even for large inputs, thanks to the logarithmic reduction in search space and linear-time feasibility checks.
The solution is elegant because it transforms an apparently complex allocation problem into a straightforward search, leveraging efficient algorithms to deliver the answer.
class Solution:
def maximumCandies(self, candies, k):
left, right = 1, max(candies)
answer = 0
def can_allocate(x):
count = 0
for pile in candies:
count += pile // x
return count >= k
while left <= right:
mid = (left + right) // 2
if can_allocate(mid):
answer = mid
left = mid + 1
else:
right = mid - 1
return answer
class Solution {
public:
long long maximumCandies(vector<int>& candies, long long k) {
long long left = 1, right = *max_element(candies.begin(), candies.end());
long long answer = 0;
auto can_allocate = [&](long long x) {
long long count = 0;
for (int pile : candies) {
count += pile / x;
if (count >= k) return true;
}
return count >= k;
};
while (left <= right) {
long long mid = left + (right - left) / 2;
if (can_allocate(mid)) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
}
};
class Solution {
public int maximumCandies(int[] candies, long k) {
int left = 1, right = 0;
for (int pile : candies) {
right = Math.max(right, pile);
}
int answer = 0;
while (left <= right) {
int mid = left + (right - left) / 2;
long count = 0;
for (int pile : candies) {
count += pile / mid;
}
if (count >= k) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
}
}
var maximumCandies = function(candies, k) {
let left = 1, right = Math.max(...candies);
let answer = 0;
function canAllocate(x) {
let count = 0;
for (let pile of candies) {
count += Math.floor(pile / x);
}
return count >= k;
}
while (left <= right) {
let mid = Math.floor((left + right) / 2);
if (canAllocate(mid)) {
answer = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return answer;
};