持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【LeetCode 1473. 粉刷房子 III 】- JavaScript(递归+记忆化)
题目描述
在一个小城市里,有 m 个房子排成一排,你需要给每个房子涂上 n 种颜色之一(颜色编号为 1 到 n )。有的房子去年夏天已经涂过颜色了,所以这些房子不可以被重新涂色。
我们将连续相同颜色尽可能多的房子称为一个街区。(比方说 houses = [1,2,2,3,3,2,1,1] ,它包含 5 个街区 [{1}, {2,2}, {3,3}, {2}, {1,1}] 。)
给你一个数组 houses ,一个 m * n 的矩阵 cost 和一个整数 target ,其中:
houses[i]:是第 i 个房子的颜色,0 表示这个房子还没有被涂色。
cost[i][j]:是将第 i 个房子涂成颜色 j+1 的花费。
请你返回房子涂色方案的最小总花费,使得每个房子都被涂色后,恰好组成 target 个街区。如果没有可用的涂色方案,请返回 -1 。
示例 1:
输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3 输出:9 解释:房子涂色方案为 [1,2,2,1,1] 此方案包含 target = 3 个街区,分别是 [{1}, {2,2}, {1,1}]。 涂色的总花费为 (1 + 1 + 1 + 1 + 5) = 9。
递归+记忆化
思路分析:
我一开始尝试直接暴力回溯,发现超时,哪怕剪枝了也没啥用,然后发现这个有很多重复查询的操作,就有套进了记忆化,减少搜索的次数。具体如下:
- 通过定义一个三维数组来记忆化结果:
cache[房子位置][右侧颜色][期望的街道数]= 最小花费。定义一个递归函数fn(房子位置,右侧颜色,期望的街道数) 返回 最小的花费。或者通过一个哈希表来缓存结果也可。- 我们发现如果该位置的颜色和右侧的颜色相同,那么期望的街道数不变,否则减一。继续调用 fn(m-1,-1,target)。
var minCost = function(houses, cost, m, n, target) {
let map = {};
function dfs(index, pieces) {
if (map[index] !== undefined && map[index][pieces] !== undefined && map[index][pieces][houses[index - 1]] !== undefined) {
return map[index][pieces][houses[index - 1]];
}
if (index == m) {
if (pieces == 0) {
return 0;
} else {
return Infinity;
}
}
if (pieces < 0) {
return Infinity;
}
let ret = Infinity;
let tmp;
let origin = houses[index];
if (origin == 0) {
for (let j = 1; j <= n; j++) {
houses[index] = j;
if (houses[index] !== houses[index - 1]) {
tmp = dfs(index + 1, pieces - 1) + cost[index][j - 1];
ret = Math.min(ret, tmp);
} else {
tmp = dfs(index + 1, pieces) + cost[index][j - 1];
ret = Math.min(ret, tmp);
}
houses[index] = origin;
}
} else {
if (houses[index] !== houses[index - 1]) {
tmp = dfs(index + 1, pieces - 1);
ret = Math.min(ret, tmp);
} else {
tmp = dfs(index + 1, pieces);
ret = Math.min(ret, tmp);
}
}
map[index] = map[index] || {};
map[index][pieces] = map[index][pieces] || {};
map[index][pieces][houses[index - 1]] = ret;
return ret;
}
let ret = dfs(0, target);
console.log(map);
return ret == Infinity ? -1 : ret;
};
注意:这道题目中的描述很让人迷惑不解,
houses[i]:是第 i 个房子的颜色,0 表示这个房子还没有被涂色。 cost[i][j]:是将第 i 个房子涂成颜色 j+1 的花费。男人看了都要落泪的那种程度。其实这道题目DP动态规划也能做,看自己怎么方便吧。感觉递归方便理解一些。
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤