安排邮筒
难度:
标签:
题目描述
给你一个房屋数组houses
和一个整数 k
,其中 houses[i]
是第 i
栋房子在一条街上的位置,现需要在这条街上安排 k
个邮筒。
请你返回每栋房子与离它最近的邮筒之间的距离的 最小 总和。
答案保证在 32 位有符号整数范围以内。
示例 1:
输入:houses = [1,4,8,10,20], k = 3 输出:5 解释:将邮筒分别安放在位置 3, 9 和 20 处。 每个房子到最近邮筒的距离和为 |3-1| + |4-3| + |9-8| + |10-9| + |20-20| = 5 。
示例 2:
输入:houses = [2,3,5,12,18], k = 2 输出:9 解释:将邮筒分别安放在位置 3 和 14 处。 每个房子到最近邮筒距离和为 |2-3| + |3-3| + |5-3| + |12-14| + |18-14| = 9 。
示例 3:
输入:houses = [7,4,6,1], k = 1 输出:8
示例 4:
输入:houses = [3,6,14,10], k = 4 输出:0
提示:
n == houses.length
1 <= n <= 100
1 <= houses[i] <= 10^4
1 <= k <= n
- 数组
houses
中的整数互不相同。
代码结果
运行时间: 73 ms, 内存: 16.8 MB
/*
* 问题描述:给定一组房屋位置和k个邮筒,找出将邮筒放置在街道上的位置,使得每栋房子到最近邮筒的距离之和最小。
*
* 思路:
* 1. 由于Java Stream API不能直接用于复杂的动态规划问题,所以我们使用stream对数组进行排序和计算距离。
*/
import java.util.Arrays;
import java.util.stream.IntStream;
public class MinDistanceToMailboxStream {
public int minDistance(int[] houses, int k) {
Arrays.sort(houses);
int n = houses.length;
int[][] dp = new int[n + 1][k + 1];
int[][] cost = new int[n + 1][n + 1];
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int median = houses[(i + j) / 2];
final int left = i;
final int right = j;
cost[i + 1][j + 1] = IntStream.rangeClosed(i, j)
.map(idx -> Math.abs(houses[idx] - median))
.sum();
}
}
IntStream.range(1, n + 1).forEach(i -> Arrays.fill(dp[i], Integer.MAX_VALUE / 2));
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
for (int m = 0; m < i; m++) {
dp[i][j] = Math.min(dp[i][j], dp[m][j - 1] + cost[m + 1][i]);
}
}
}
return dp[n][k];
}
}
解释
方法:
这个问题可以通过动态规划来解决。首先,我们对房屋位置进行排序,使得问题变得更容易处理。定义dp[i][j]表示前i+1个房屋安排j个邮筒的最小距离总和。数组one[i][j]用于存储从i到j的房子只用一个邮筒时的最小总距离,其中邮筒放在中位数位置能够达到最小距离。我们首先计算所有可能的one[i][j]值。然后,使用动态规划填充dp数组。对于每个dp[i][j],我们尝试所有可能的前一个状态dp[k][j-1](其中k < i),并加上从k+1到i的房屋使用一个邮筒的距离,即one[k+1][i]。通过这种方式,我们可以构建出所有房屋和邮筒配置的最小距离总和。
时间复杂度:
O(n^2 * k)
空间复杂度:
O(n^2 + n * k)
代码细节讲解
🦆
为什么在解题中首先需要对房屋的位置进行排序?排序的目的和效果是什么?
▷🦆
在计算one数组时,为什么选择邮筒放在中位数位置能达到最小总距离,这个逻辑是如何得出的?
▷🦆
one数组中的p1和p2的计算公式是如何推导出来的,能否详细解释一下它们的含义?
▷