You are given a 0-indexed integer array candies
. Each element in the array denotes a pile of candies of size candies[i]
. You can divide each pile into any number of sub piles, but you cannot merge two piles together.
You are also given an integer k
. You should allocate piles of candies to k
children such that each child gets the same number of candies. Each child can be allocated candies from only one pile of candies and some piles of candies may go unused.
Return the maximum number of candies each child can get.
Example 1:
Input: candies = [5,8,6], k = 3 Output: 5 Explanation: We can divide candies[1] into 2 piles of size 5 and 3, and candies[2] into 2 piles of size 5 and 1. We now have five piles of candies of sizes 5, 5, 3, 5, and 1. We can allocate the 3 piles of size 5 to 3 children. It can be proven that each child cannot receive more than 5 candies.
Example 2:
Input: candies = [2,5], k = 11 Output: 0 Explanation: There are 11 children but only 7 candies in total, so it is impossible to ensure each child receives at least one candy. Thus, each child gets no candy and the answer is 0.
Constraints:
1 <= candies.length <= 105
1 <= candies[i] <= 107
1 <= k <= 1012
This problem asks to find the maximum number of candies each of k children can get, given an array of candy piles and the restriction that each child can take at most one pile. We can't merge piles, but we can split them.
The key observation is that the maximum number of candies each child can receive exhibits a monotonically decreasing property. If we can distribute x
candies per child, we can also distribute any number less than x
. This property allows us to efficiently use binary search.
Approach:
Binary Search: We perform a binary search on the possible range of candies per child. The search space is [0, max(candies)], where max(candies) is the largest pile of candies.
Check Feasibility: In each iteration of the binary search, we check if it's possible to distribute mid
(the middle value in the search space) candies to each child. This is done by calculating the total number of children we can satisfy with mid
candies per child:
candies[i]
, we calculate candies[i] / mid
, which represents how many children can be satisfied from this pile.k
, it means we can distribute mid
candies to each of k
children.Adjust Search Space:
k
, it means mid
is a feasible amount of candies per child, so we update the left boundary of the search space to mid
. This is because we're trying to find the maximum possible amount.mid
is too high, and we update the right boundary to mid - 1
.Return Result: The binary search continues until the left and right boundaries converge (l == r
). At this point, l
(or r
) represents the maximum number of candies each child can receive.
Time Complexity: O(N log M), where N is the number of candy piles and M is the maximum number of candies in a pile. The binary search takes O(log M) iterations, and each iteration requires O(N) time to check feasibility.
Space Complexity: O(1). The algorithm uses a constant amount of extra space.
Code Examples:
The code examples below demonstrate the solution in several programming languages. They all follow the same binary search algorithm outlined above.
def maximumCandies(candies, k):
left, right = 0, max(candies)
while left < right:
mid = (left + right + 1) // 2 # Integer division for mid
total_children = sum(candy // mid for candy in candies)
if total_children >= k:
left = mid
else:
right = mid - 1
return left
class Solution {
public int maximumCandies(int[] candies, long k) {
int left = 0, right = Arrays.stream(candies).max().getAsInt();
while (left < right) {
int mid = (left + right + 1) / 2;
long totalChildren = 0;
for (int candy : candies) {
totalChildren += candy / mid;
}
if (totalChildren >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
}
#include <algorithm>
#include <numeric>
class Solution {
public:
int maximumCandies(vector<int>& candies, long long k) {
int left = 0, right = *max_element(candies.begin(), candies.end());
while (left < right) {
int mid = (left + right + 1) / 2;
long long totalChildren = 0;
for (int candy : candies) {
totalChildren += candy / mid;
}
if (totalChildren >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
};
func maximumCandies(candies []int, k int64) int {
left, right := 0, 0
for _, c := range candies {
if c > right {
right = c
}
}
for left < right {
mid := (left + right + 1) / 2
totalChildren := int64(0)
for _, candy := range candies {
totalChildren += int64(candy / mid)
}
if totalChildren >= k {
left = mid
} else {
right = mid - 1
}
}
return left
}
/**
* @param {number[]} candies
* @param {number} k
* @return {number}
*/
var maximumCandies = function(candies, k) {
let left = 0;
let right = Math.max(...candies);
while (left < right) {
let mid = Math.floor((left + right + 1) / 2);
let totalChildren = 0;
for (let candy of candies) {
totalChildren += Math.floor(candy / mid);
}
if (totalChildren >= k) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
};
These codes all implement the same efficient binary search approach to solve the problem. Remember to choose the code that best suits your preferred programming language.