class Solution {
public:
int minDistance(vector<int>& houses, int k) {
}
};
1478. 安排邮筒
给你一个房屋数组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
中的整数互不相同。原站题解
python3 解法, 执行用时: 360 ms, 内存消耗: 16.4 MB, 提交时间: 2023-06-21 17:58:39
class Solution: def minDistance(self, houses: List[int], k: int) -> int: houses.sort() n = len(houses) cost = [[0] * n for _ in range(n)] presum = [0] + list(accumulate(houses)) for i in range(n): for j in range(i, n): l = j - i + 1 point = i + l//2 cost[i][j] = presum[j + 1] - presum[point] * 2 + presum[i] - (houses[point] if l % 2 else 0) dp = list(cost[0]) for _ in range(k - 1): for i in range(n-1, -1, -1): for j in range(i): dp[i] = min(dp[i], dp[j] + cost[j+1][i]) return dp[-1]
golang 解法, 执行用时: 0 ms, 内存消耗: 3.1 MB, 提交时间: 2023-06-21 17:58:21
func minDistance(houses []int, k int) int { sort.Ints(houses) n := len(houses) presum := make([]int, n + 1) for i := 0; i < n; i++ { presum[i + 1] = presum[i] + houses[i]; } cost := make([][]int, n) for i := 0; i < n; i++ { cost[i] = make([]int, n) for j := i; j < n; j++ { l := j - i + 1 point := i + l / 2 cost[i][j] = presum[j + 1] - presum[point] * 2 + presum[i] if l & 1 > 0 { cost[i][j] -= houses[point] } } } dp := make([]int, n) copy(dp, cost[0]) for m := 0; m < k - 1; m++ { for r := n - 1; r >= 0; r-- { for l := 0; l < r; l++ { if v:= dp[l] + cost[l + 1][r]; v < dp[r]{ dp[r] = v } } } } return dp[n - 1] }
java 解法, 执行用时: 7 ms, 内存消耗: 39.7 MB, 提交时间: 2023-06-21 17:57:20
class Solution { public int minDistance(int[] houses, int k) { int n = houses.length; Arrays.sort(houses); int[][] medsum = new int[n][n]; for (int i = n - 2; i >= 0; --i) { for (int j = i + 1; j < n; ++j) { medsum[i][j] = medsum[i + 1][j - 1] + houses[j] - houses[i]; } } int[][] f = new int[n][k + 1]; for (int i = 0; i < n; ++i) { Arrays.fill(f[i], Integer.MAX_VALUE / 2); } for (int i = 0; i < n; ++i) { f[i][1] = medsum[0][i]; for (int j = 2; j <= k && j <= i + 1; ++j) { for (int i0 = 0; i0 < i; ++i0) { f[i][j] = Math.min(f[i][j], f[i0][j - 1] + medsum[i0 + 1][i]); } } } return f[n - 1][k]; } }
python3 解法, 执行用时: 304 ms, 内存消耗: 16.7 MB, 提交时间: 2023-06-21 17:56:59
class Solution: def minDistance(self, houses: List[int], k: int) -> int: n = len(houses) houses.sort() medsum = [[0] * n for _ in range(n)] for i in range(n - 2, -1, -1): for j in range(i + 1, n): medsum[i][j] = medsum[i + 1][j - 1] + houses[j] - houses[i] BIG = 10**9 f = [[BIG] * (k + 1) for _ in range(n)] for i in range(n): f[i][1] = medsum[0][i] for j in range(2, min(k, i + 1) + 1): for i0 in range(i): if f[i0][j - 1] != BIG: f[i][j] = min(f[i][j], f[i0][j - 1] + medsum[i0 + 1][i]) return f[n - 1][k]
cpp 解法, 执行用时: 36 ms, 内存消耗: 9.2 MB, 提交时间: 2023-06-21 17:56:19
/** * 动态规划 * dp[i][j] 前i个房子放置j个邮箱的最小距离 * **/ class Solution { public: int minDistance(vector<int>& houses, int k) { int n=houses.size(); //排序 sort(houses.begin(),houses.end()); //计算最小花费 vector<vector<int>> d(n,vector<int>(n,1e8)); //初始化 for(int i=0;i<n;i++) d[i][i]=0; for(int i=0;i<n-1;i++) d[i][i+1]=houses[i+1]-houses[i]; //状态转移 for(int j=2;j<n;j++){ for(int i=j-2;i>=0;i--){ d[i][j]=d[i+1][j-1]+houses[j]-houses[i]; } } //dp vector<vector<int>> dp(n,vector<int>(k+1,1e8)); //初始化 for(int i=0;i<n;i++) dp[i][1]=d[0][i]; for(int j=2;j<=k;j++){ for(int i=j-1;i<n;i++){ //穷举分割状态转移 for(int xt=0;xt<i;xt++){ dp[i][j]=min(dp[i][j],dp[xt][j-1]+d[xt+1][i]); } } } return dp[n-1][k]; } };
python3 解法, 执行用时: 292 ms, 内存消耗: 17.5 MB, 提交时间: 2023-06-21 17:53:21
# 记忆化 + dfs class Solution: def minDistance(self, houses: List[int], k: int) -> int: houses.sort() pre = [0] l = len(houses) for i in range(l): pre.append(pre[-1] + houses[i]) #i, k分别是房屋下标和剩余邮筒数量 @lru_cache(None) def dfs(i: int, k: int): #如果邮筒数量大于等于房子数量,那么距离和一定为0 if l - i <= k: return 0 #如果邮筒数量为1 elif k == 1: #中位数 j = (l + i) // 2 #中位数 * 左区间大小 - 左区间和 + 右区间和 - 中位数 * 右区间大小 return houses[j] * (j - i) - (pre[j] - pre[i]) + pre[l] - pre[j] - houses[j] * (l - j) #当前邮筒只覆盖一个房子 res = dfs(i + 1, k - 1) #覆盖多个房子 for n in range(i + 1, l): #中位数 j = (n + 1 + i) // 2 #中位数 * 左区间大小 - 左区间和 + 右区间和 - 中位数 * 右区间大小 + 继续深搜的结果 res = min(res, houses[j] * (j - i) - (pre[j] - pre[i]) + pre[n + 1] - pre[j] - houses[j] * (n + 1 - j) + dfs(n + 1, k - 1)) return res return dfs(0, k)