🌈【LeetCode 1473. 粉刷房子 III 】- JavaScript(递归+记忆化)

130 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情


说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)

作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金

GitHub:P-J27、 CSDN:PJ想做前端攻城狮

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


【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动态规划也能做,看自己怎么方便吧。感觉递归方便理解一些。


感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。

写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤