剑指 Offer II 091. 粉刷房子(256. 粉刷房子)
题目:
思路:
【1】动态规划的方式,首先对于动态规划的问题是分成子问题,那么子问题又可以当做是一个小汇总,如
对于 1≤i<n,第 i 号房子和第 i−1 号房子的颜色必须不同,
因此当第 i 号房子被粉刷成某一种颜色时,第 i−1 号房子只能被粉刷成另外两种颜色之一。
当第 i 号房子分别被粉刷成三种颜色时,粉刷第 0 号房子到第 i 号房子的最小花费成本计算如下:
dp[i][0]=min(dp[i−1][1],dp[i−1][2])+costs[i][0]
dp[i][1]=min(dp[i−1][0],dp[i−1][2])+costs[i][1]
dp[i][2]=min(dp[i−1][0],dp[i−1][1])+costs[i][2]
三种颜色的情况可以合并为一个状态转移方程,对于 1≤i<n 和 0≤j<3,状态转移方程如下:
dp[i][j]=min(dp[i−1][(j+1) mod 3],dp[i−1][(j+2) mod 3])+costs[i][j]
计算结束时,dp[n−1] 中的最小值即为粉刷所有房子的最小花费成本。
代码展示:
动态规划的方式:
//时间2 ms击败16.60% //内存40.9 MB击败60.2% //时间复杂度:O(n),其中 n 是房子个数。 //需要遍历全部房子一次,由于颜色数量固定是三种,因此对于每个房子计算粉刷房子的最小花费成本的时间是 O(1),总时间复杂度是 O(n)。 //空间复杂度:O(1)。使用空间优化的方法,只需要维护一个长度为 3 的数组,空间复杂度是 O(1)。 class Solution { public int minCost(int[][] costs) { int n = costs.length; int[] dp = new int[3]; for (int j = 0; j < 3; j++) { dp[j] = costs[0][j]; } for (int i = 1; i < n; i++) { int[] dpNew = new int[3]; for (int j = 0; j < 3; j++) { dpNew[j] = Math.min(dp[(j + 1) % 3], dp[(j + 2) % 3]) + costs[i][j]; } dp = dpNew; } return Arrays.stream(dp).min().getAsInt(); } } //在原本的数组上进行统计 //时间1 ms击败84.11% //内存40.8 MB击败64.27% class Solution { public int minCost(int[][] costs) { int n=costs.length; for(int i=1;i<n;i++){ costs[i][0]+=Math.min(costs[i-1][2],costs[i-1][1]); costs[i][1]+=Math.min(costs[i-1][2],costs[i-1][0]); costs[i][2]+=Math.min(costs[i-1][0],costs[i-1][1]); } return Math.min(costs[n-1][0],Math.min(costs[n-1][1],costs[n-1][2])); } }