Greedy · 20 of 35
Minimum sum of absolute difference of pairs of two arrays
Pair up two lists of numbers so the pairs are as close as possible, by sorting both lists and matching them in order.
- Simple way
- time O(n! * n)
room O(n) - Clever way
- time O(n log n)
room O(1)
The problem, simply
You get two lists, a and b, with the same number of numbers. Pair every number in a with exactly one number in b. A pair costs the gap between its two numbers, |a[i] - b[j]|.
Give back the smallest possible total cost of all pairs.
A story to remember it
Picture it
a = [4, 1, 8, 7] and b = [2, 3, 6, 5]. After sorting, each number lines up with its partner straight below it.
Examples
A normal case
- In
a = [4, 1, 8, 7], b = [2, 3, 6, 5]- Out
6
Sorted, the pairs are (1, 2), (4, 3), (7, 5), (8, 6), with gaps 1 + 1 + 2 + 2 = 6.
Same numbers, different order
- In
a = [3, 2, 1], b = [2, 1, 3]- Out
0
Every number finds its twin, so every gap is 0.
Negative numbers
- In
a = [-5, 10], b = [0, -3]- Out
12
Sorted, the pairs are (-5, -3) and (10, 0), with gaps 2 + 10 = 12. The other way, (-5, 0) and (10, -3), costs 5 + 13 = 18.
One pair
- In
a = [7], b = [2]- Out
5
There is only one way to pair them.
Way 1: the simple way
Keep a in place and try every order of b. Each order is one way to pair the lists. Add up the gaps and keep the smallest total.
class Solution {
private long best;
public long minPairGap(int[] a, int[] b) {
best = Long.MAX_VALUE;
tryOrders(a, b, 0);
return best;
}
private void tryOrders(int[] a, int[] b, int start) {
if (start == b.length) {
long total = 0;
for (int i = 0; i < a.length; i++) total += Math.abs((long) a[i] - b[i]);
best = Math.min(best, total);
return;
}
for (int i = start; i < b.length; i++) {
swap(b, start, i); // choose who partners a[start]
tryOrders(a, b, start + 1);
swap(b, start, i);
}
}
private void swap(int[] x, int i, int j) { int t = x[i]; x[i] = x[j]; x[j] = t; }
}How long it takes: n! pairings, each added up in n steps, so O(n! * n). Extra room: recursion n deep, O(n).
Way 2: the clever way
Crossed pairs are never better. Say x <= y in a and p <= q in b. Pairing x with q and y with p crosses the pairs. Pairing x with p and y with q keeps them straight, and on a number line you can check that the straight pairs never cost more. So fix every crossing and you end with both lists in sorted order.
a1 and a4 are the numbers 1 and 4 from list a, b2 and b3 are 2 and 3 from list b. The crossed pairs cost 2 + 2 = 4. The straight pairs cost 1 + 1 = 2.
- done
- rejected
- Sort
a. - Sort
b. - Add
|a[i] - b[i]|for everyi.
Sort both lists and pair them in order
01 / 07
Two lists of four. Each number in a must hold hands with exactly one number in b. A pair costs the gap between the two numbers.
- looking now
- done
- answer
- just added
import java.util.Arrays;
class Solution {
public long minPairGap(int[] a, int[] b) {
Arrays.sort(a);
Arrays.sort(b);
long total = 0;
for (int i = 0; i < a.length; i++) {
total += Math.abs((long) a[i] - b[i]); // i-th smallest with i-th smallest
}
return total;
}
}How long it takes: two sorts, O(n log n), then one walk, O(n). Extra room: O(1) beyond sorting in place.
Watch out for
- Sort both lists the same way, both small to big. Sorting one up and one down gives the largest total, not the smallest.
- The lists must have the same length. If they do not, the problem is different (see below).
- The answer only needs the total. If you must report the pairs, remember each number's original index before sorting.
What interviewers ask next
- The largest total instead? Sort one list up and the other down, so the smallest meets the biggest.
- What if
bis longer and each number inamust pick a different partner fromb? Now some numbers inbare left out, and greedy is not enough. Use dynamic programming over both sorted lists:dp[i][j]is the best cost using the firstiofaand the firstjofb. - What if the cost is a general table, not a gap on a number line? That is the assignment problem, solved by the Hungarian algorithm in
O(n^3). - The pairs are fixed by position (
a[i]withb[i]), and you may overwrite onea[i]with a copy of any other number froma. Sort a copy ofaand, for eachb[i], binary search the closest value to see how much that one change saves. This is LeetCode "Minimum Absolute Sum Difference".
Remember this
Grown-up words: the dance pairs are a matching, the cost is the sum of absolute differences, and uncrossing pairs is an exchange argument.