Skip to content

1478. Allocate Mailboxes 👍

  • Time: $O(n^3 + kn^2) = O(n^3)$;
  • Space: $O(n^2)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
 public:
  int minDistance(vector<int>& houses, int k) {
    const int n = houses.size();
    vector<vector<int>> mem(n, vector<int>(k + 1, INT_MAX));
    // cost[i][j] := the minimum cost to allocate mailboxes between houses[i]
    // and houses[j]
    vector<vector<int>> cost(n, vector<int>(n));

    ranges::sort(houses);

    for (int i = 0; i < n; ++i)
      for (int j = i + 1; j < n; ++j) {
        const int median = houses[(i + j) / 2];
        for (int x = i; x <= j; ++x)
          cost[i][j] += abs(houses[x] - median);
      }

    return minDistance(houses, 0, k, cost, mem);
  }

 private:
  static constexpr int kMax = 1'000'000;

  // Returns the minimum distance to allocate k mailboxes for houses[i..n).
  int minDistance(const vector<int>& houses, int i, int k,
                  const vector<vector<int>>& cost, vector<vector<int>>& mem) {
    if (i == houses.size() && k == 0)
      return 0;
    if (i == houses.size() || k == 0)
      return kMax;
    if (mem[i][k] != INT_MAX)
      return mem[i][k];

    for (int j = i; j < houses.size(); ++j)
      mem[i][k] = min(
          mem[i][k], cost[i][j] + minDistance(houses, j + 1, k - 1, cost, mem));

    return mem[i][k];
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
  public int minDistance(int[] houses, int k) {
    final int n = houses.length;
    int[][] mem = new int[n][k + 1];
    // cost[i][j] := the minimum cost to allocate mailboxes between houses[i]
    // and houses[j]
    int[][] cost = new int[n][n];

    Arrays.stream(mem).forEach(A -> Arrays.fill(A, Integer.MAX_VALUE));
    Arrays.sort(houses);

    for (int i = 0; i < n; ++i)
      for (int j = i + 1; j < n; ++j) {
        int median = houses[(i + j) / 2];
        for (int x = i; x <= j; ++x)
          cost[i][j] += Math.abs(houses[x] - median);
      }

    return minDistance(houses, 0, k, cost, mem);
  }

  private static final int kMax = 1_000_000;

  // Returns the minimum distance to allocate k mailboxes for houses[i..n).
  private int minDistance(int[] houses, int i, int k, int[][] cost, int[][] mem) {
    if (i == houses.length && k == 0)
      return 0;
    if (i == houses.length || k == 0)
      return kMax;
    if (mem[i][k] != Integer.MAX_VALUE)
      return mem[i][k];

    for (int j = i; j < houses.length; ++j)
      mem[i][k] = Math.min(mem[i][k], cost[i][j] + minDistance(houses, j + 1, k - 1, cost, mem));

    return mem[i][k];
  }
}