「图解大厂面试高频算法题」动态规划-粉刷房子I
2021/12/14 22:17:29
本文主要是介绍「图解大厂面试高频算法题」动态规划-粉刷房子I,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
「图解大厂面试高频算法题」动态规划-粉刷房子I
原题链接: https://leetcode-cn.com/problems/paint-house/
题目介绍
题目解答
又又又又是动态规划,动态规划的要点是啥来着?发现子问题、找出状态转换方程、优化数组空间。
首先寻找子问题
题目的原问题是求解粉刷从第0到第N个房子红/蓝/绿这三种颜色所花费的最低开销,这个问题可以拆成如下N个子问题
- 粉刷第0个房子红/蓝/绿这三种颜色所花费的最低开销
- 粉刷从第0到第1个房子红/蓝/绿这三种颜色所花费的最低开销
- … …
- 粉刷从第0到第N-1个房子红/蓝/绿这三种颜色所花费的最低开销
- 粉刷从第0到第N个房子红/蓝/绿这三种颜色所花费的最低开销
注意这题有一个限制就是相邻的两个房子颜色不能相同,所以小粉刷匠每刷一个房子的时候,他需要思考这个房子要刷哪种颜色,刷红色?刷蓝色?刷绿色?这样每一个子问题又可以继续拆解变成如下3N个子问题
- 粉刷第0个房子红/蓝/绿这三种颜色所花费的最低开销
- 给第0个房子刷红色时,粉刷从第0到第0个房子的最低开销是多少?
- 给第0个房子刷蓝色时,粉刷从第0到第0个房子的最低开销是多少?
- 给第0个房子刷绿色时,粉刷从第0到第0个房子的最低开销是多少?
- 粉刷从第0到第1个房子红/蓝/绿这三种颜色所花费的最低开销
- 给第1个房子刷红色时,粉刷从第0到第1个房子的最低开销是多少?
- 给第1个房子刷蓝色时,粉刷从第0到第1个房子的最低开销是多少?
- 给第1个房子刷绿色时,粉刷从第0到第1个房子的最低开销是多少?
- … …
- 粉刷从第0到第N-1个房子红/蓝/绿这三种颜色所花费的最低开销
- 给第N-1个房子刷红色时,粉刷从第0到第N-1个房子的最低开销是多少?
- 给第N-1个房子刷蓝色时,粉刷从第0到第N-1个房子的最低开销是多少?
- 给第N-1个房子刷绿色时,粉刷从第0到第N-1个房子的最低开销是多少?
- 粉刷从第0到第N个房子红/蓝/绿这三种颜色所花费的最低开销
- 给第N个房子刷红色时,粉刷从第0到第N个房子的最低开销是多少?
- 给第N个房子刷蓝色时,粉刷从第0到第N个房子的最低开销是多少?
- 给第N个房子刷绿色时,粉刷从第0到第N个房子的最低开销是多少?
确定状态转移方程
子问题已经确定出来了,那么如果我们知道了粉刷从第0到第N-1个房子红/蓝/绿这三种颜色所花费的最低开销,那么我们如何根据这个子问题来算出原问题粉刷从第0到第N个房子红/蓝/绿这三种颜色所花费的最低开销呢?
粉刷匠为了让开销达到最小,自学了编程然后搞了3个数组red、blue和green,red[k]表示粉刷从第0到第k个房子红/蓝/绿这三种颜色所花费的最低开销,其中第k个房子粉刷为红色,blue[k]和green[k]亦然,粉刷匠每到达一个房子的时候,都会去更新red[k]、blue[k]和green[k],当粉刷匠来到了第K个房子的时心里可能这么想:
- 我要把第K个房子刷为红色
- 粉刷匠决定把第K个房子刷为红色,并记录下当前第K个房子刷为红色时所花费的最低开销为red[k] = min(blue[k-1], green[k-1]) + cost[k]。
- 解释: 既然粉刷匠想把第K个房子刷为红色,且想保持所花费的开销是最低的,那第K-1一个房子不能是红色的且要选择blue[k-1]和green[k-1]这两个数其中最小的一个。
- 我要把第K个房子刷为蓝色
- 同上
- 我要把第K个房子刷为蓝色
- 同上
那么我们得出了状态转移方程如下
red[k] = min(blue[k-1], green[k-1]) + cost[k]
blue[k] = min(red[k-1], green[k-1]) + cost[k]
green[k] = min(blue[k-1], red[k-1]) + cost[k]
有了状态转移方程, 那就很容易写出代码了
代码实现(一维动态规划)
class Solution { public int minCost(int[][] costs) { int[][] dp = new int[costs.length][3]; // 0 - 红色 // 1 - 蓝色 // 2 - 绿色 dp[0][0] = costs[0][0]; dp[0][1] = costs[0][1]; dp[0][2] = costs[0][2]; for (int i = 1; i < costs.length; i++) { dp[i][0] = Math.min(dp[i-1][1], dp[i-1][2]) + costs[i][0]; dp[i][1] = Math.min(dp[i-1][0], dp[i-1][2]) + costs[i][1]; dp[i][2] = Math.min(dp[i-1][0], dp[i-1][1]) + costs[i][2]; } return Math.min(dp[costs.length-1][0], Math.min(dp[costs.length-1][1], dp[costs.length-1][2])); } }
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(n)
优化空间
上面的一维动态规划解法使用了一个dp数组,我们仔细观察可以发现,计算dp[i]的状态只取决于dp[i-1]的状态,所以我们可以用三个临时变量red/blue/green来代替dp[i-1][0]/dp[i-1][1]/dp[i-1][2]中的值。
class Solution { public int minCost(int[][] costs) { int[][] dp = new int[costs.length][3]; int redCost = costs[0][0], blueCost = costs[0][1], greenCost = costs[0][2]; for (int i = 1; i < costs.length; i++) { int newRedCost = Math.min(blueCost, greenCost) + costs[i][0]; int newBlueCost = Math.min(redCost, greenCost) + costs[i][1]; int newGreenCost = Math.min(redCost, blueCost) + costs[i][2]; redCost = newRedCost; blueCost = newBlueCost; greenCost = newGreenCost; } return Math.min(redCost, Math.min(blueCost, greenCost)); } }
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(1)
这篇关于「图解大厂面试高频算法题」动态规划-粉刷房子I的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南