Allocate Mailboxes — Hard Problem & Solution
houses[i] is the position of the i-th house on a street. Place exactly k mailboxes anywhere along the street.
- Difficulty: Hard
- Topics: Arrays, Math, Dynamic Programming, Sorting
- Asked at: Amazon, Google, Microsoft
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
houses[i] is the position of the i-th house on a street. Place exactly k mailboxes anywhere along the street.
Return the minimum total distance between each house and its nearest mailbox.
Example 1
Input: houses = [1,4,8,10,20], k = 3
Output: 5
Explanation: Mailboxes at 3, 9 and 20 cost 2 + 1 + 1 + 1 + 0.
Example 2
Input: houses = [2,3,5,12,18], k = 2
Output: 9
Explanation: One mailbox covers 2, 3, 5 and another covers 12 and 18.
Example 3
Input: houses = [7,4,6,1], k = 1
Output: 8
Constraints
1 <= k <= houses.length <= 1001 <= houses[i] <= 10^4All the integers of houses are unique.
How to solve Allocate Mailboxes
Sort the houses; an optimal solution assigns each mailbox a contiguous run. Precompute cost[i][j] — the total distance when a single mailbox serves houses i..j, which is minimised by placing it at the median. Then a partition DP over the number of mailboxes finishes it.
Approach
- Sort
houses. - For every
i <= j, computecost[i][j]as the sum of|h[t] - median|over the block. - Set
dp[0][0] = 0anddp[g][j] = min over i < j of dp[g-1][i] + cost[i][j-1]. - Return
dp[k][n].
Why it works
Two facts carry the solution. Contiguity: if a mailbox served a non-contiguous set, some house would be closer to another mailbox — so blocks never interleave, and a partition DP is exhaustive. The median: for absolute deviations on a line the median is the minimiser, which is why each block's cost is a single precomputable number rather than another search.
Complexity
- Time —
O(n³) for the cost table plus O(k · n²) for the DP - Space —
O(n² + k · n)
Pitfalls
- The positions arrive unsorted; the contiguity argument only holds after sorting.
- The median, not the mean, minimises the sum of absolute distances.
- Exactly
kmailboxes must be placed, though two may coincide whenkexceeds what is useful.
Reference solution
Python
from typing import List
def minDistance(houses: List[int], k: int) -> int:
h = sorted(houses)
n = len(h)
INF = 10**9
cost = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(i, n):
mid = h[(i + j) // 2]
cost[i][j] = sum(abs(h[t] - mid) for t in range(i, j + 1))
dp = [[INF] * (n + 1) for _ in range(k + 1)]
dp[0][0] = 0
for g in range(1, k + 1):
for j in range(1, n + 1):
for i in range(j):
if dp[g - 1][i] == INF:
continue
dp[g][j] = min(dp[g][j], dp[g - 1][i] + cost[i][j - 1])
return dp[k][n]JavaScript
var minDistance = function(houses, k) {
var h = houses.slice();
h.sort(function(a, b) { return a - b; });
var n = h.length, INF = 1000000000, i, j, t;
var cost = [];
for (i = 0; i < n; i++) {
var row = [];
for (j = 0; j < n; j++) row.push(0);
cost.push(row);
}
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
var total = 0;
var mid = h[Math.floor((i + j) / 2)];
for (t = i; t <= j; t++) total += h[t] > mid ? h[t] - mid : mid - h[t];
cost[i][j] = total;
}
}
var dp = [];
for (var g = 0; g <= k; g++) {
var r = [];
for (j = 0; j <= n; j++) r.push(INF);
dp.push(r);
}
dp[0][0] = 0;
for (g = 1; g <= k; g++) {
for (j = 1; j <= n; j++) {
for (i = 0; i < j; i++) {
if (dp[g - 1][i] === INF) continue;
var cand = dp[g - 1][i] + cost[i][j - 1];
if (cand < dp[g][j]) dp[g][j] = cand;
}
}
}
return dp[k][n];
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.