Array · 20 of 36
Chocolate Distribution problem
Hand one chocolate packet to each kid so the biggest and smallest packets given out are as close as possible.
- Simple way
- time O(C(n, m) * m)
room O(m) - Clever way
- time O(n log n)
room O(1)
The problem, simply
You have n packets of chocolate. arr[i] is how many chocolates are in packet i. There are m kids, and each kid gets exactly one packet.
Pick m packets so that the difference between the fullest packet and the emptiest packet you hand out is as small as possible. Give back that smallest difference.
A story to remember it
Picture it
Seven packets, three kids. After sorting, the packets 2, 3 and 4 sit together, and their gap is only 4 - 2 = 2.
- answer
Examples
A normal case
- In
arr = [7, 3, 2, 4, 9, 12, 56], m = 3- Out
2
Hand out 2, 3 and 4. The fullest is 4, the emptiest is 2, and 4 - 2 = 2.
Repeated sizes
- In
arr = [3, 4, 1, 9, 56, 7, 9, 12], m = 5- Out
6
Sorted: 1, 3, 4, 7, 9, 9, 12, 56. The frame 3, 4, 7, 9, 9 has gap 9 - 3 = 6, the smallest of all frames of five.
One kid
- In
arr = [5, 8, 1], m = 1- Out
0
One packet is both the fullest and the emptiest, so the gap is 0.
Not enough packets
- In
arr = [4, 2], m = 3- Out
-1
Three kids cannot each get a packet from two packets. Return -1, or whatever the problem says for impossible.
Way 1: the simple way
Try every way to choose m packets out of n. For each choice, find its biggest and smallest packet and keep the smallest gap.
- Build groups one packet at a time: for each packet, either put it in the group or skip it.
- When a group has
mpackets, computemax - minand keep the best.
class Solution {
private int best;
public int findMinDiff(int[] arr, int m) {
if (m == 0 || m > arr.length) return -1;
best = Integer.MAX_VALUE;
choose(arr, m, 0, new ArrayList<>());
return best;
}
private void choose(int[] arr, int m, int start, List<Integer> group) {
if (group.size() == m) { // a full group of packets
best = Math.min(best, Collections.max(group) - Collections.min(group));
return;
}
for (int i = start; i < arr.length; i++) {
group.add(arr[i]); // take packet i
choose(arr, m, i + 1, group);
group.remove(group.size() - 1); // put it back
}
}
}How long it takes: there are "n choose m" groups, written C(n, m), and each costs O(m) to check, so O(C(n, m) * m). For 50 packets and 25 kids that is more than a hundred trillion groups. Extra room: the group being built, O(m).
Way 2: the clever way
Sort the packets first. Now look at any good group. Its emptiest packet is some arr[i]. The best partners for it are the next m - 1 packets to its right, because any packet further right is bigger and can only make the gap worse. So the best group is always m packets that sit next to each other in sorted order.
- Sort
arr. - For every start
ifrom0ton - m, the group isarr[i]toarr[i + m - 1], and its gap isarr[i + m - 1] - arr[i]. - Keep the smallest gap.
Sort, then slide a frame of m packets
01 / 08
Seven packets in the order we got them. Three kids are waiting, so m = 3.
- m
- 3
- checking
- done
- answer
class Solution {
public int findMinDiff(int[] arr, int m) {
int n = arr.length;
if (m == 0 || m > n) return -1;
Arrays.sort(arr); // line the bags up
int best = Integer.MAX_VALUE;
for (int i = 0; i + m - 1 < n; i++) {
int gap = arr[i + m - 1] - arr[i]; // last in frame minus first
best = Math.min(best, gap);
}
return best;
}
}How long it takes: sorting is O(n log n) and the slide is O(n), so O(n log n) in total. Extra room: a few numbers, O(1) (Java's sort for int[] uses a little stack space, about O(log n)).
Watch out for
- The window covers
arr[i]toarr[i + m - 1], notarr[i + m]. Off by one here is the classic slip. - Check
m > nandm == 0before sorting. - Sorting changes the caller's array. Copy it first if the input must stay the same.
What interviewers ask next
- Return the actual packets, not only the gap. Remember the start
iof the best frame and returnarr[i..i+m-1]. - Can you avoid the sort? If the chocolate counts are small numbers, a counting sort makes it
O(n + maxValue). - Why is a block of neighbours always optimal? Fix the smallest packet in the best group. Swapping any other packet for a smaller unused one to its right never raises the maximum, so you can slide all of them next to the smallest.
- A cousin problem: make the heights of towers as even as possible by adding or removing
k. That one also starts by sorting.
Remember this
Grown-up words: lining up the bags is sorting, the cardboard frame is a fixed size sliding window, and the unfairness is the range (max minus min) of the chosen subset.