目录
1. 粉刷房子 Paint House
2. 粉刷房子 II Paint House-ii
3. 粉刷房子 III Paint House-iii
🌟 每日一练刷题专栏 🌟
Golang每日一练 专栏
Python每日一练 专栏
C/C++每日一练 专栏
Java每日一练 专栏
leetcode题号分别为: 256、265、1473
1. 粉刷房子 Paint House
假如有一排房子,共 n
个,每个房子可以被粉刷成红色、蓝色或者绿色这三种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。每个房子粉刷成不同颜色的花费是以一个 n x 3
的正整数矩阵 costs
来表示的。
例如,costs[0][0]
表示第 0 号房子粉刷成红色的成本花费;costs[1][2]
表示第 1 号房子粉刷成绿色的花费,以此类推。
请计算出粉刷完所有房子最少的花费成本。
示例 1:
输入: costs = [[17,2,17],[16,16,5],[14,3,19]] 输出: 10 解释: 将 0 号房子粉刷成蓝色,1 号房子粉刷成绿色,2 号房子粉刷成蓝色。 最少花费: 2 + 5 + 3 = 10。
示例 2:
输入: costs = [[7,6,2]] 输出: 2
提示:
costs.length == n
costs[i].length == 3
1 <= n <= 100
1 <= costs[i][j] <= 20
代码1:
from typing import List
class Solution:
def minCost(self, costs: List[List[int]]) -> int:
n = len(costs)
dp = [[0] * 3 for _ in range(n)]
dp[0][0], dp[0][1], dp[0][2] = costs[0][0], costs[0][1], costs[0][2]
for i in range(1, n):
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]
return min(dp[n-1])
# %%
s = Solution()
print(s.minCost(costs = [[17,2,17],[16,16,5],[14,3,19]]))
print(s.minCost(costs = [[7,6,2]]))
代码2:
from typing import List
class Solution:
def minCost(self, costs: List[List[int]]) -> int:
n = len(costs)
dp0, dp1, dp2 = costs[0][0], costs[0][1], costs[0][2]
for i in range(1, n):
dp0, dp1, dp2 = min(dp1, dp2) + costs[i][0], min(dp0, dp2) + costs[i][1], min(dp0, dp1) + costs[i][2]
return min(dp0, dp1, dp2)
# %%
s = Solution()
print(s.minCost(costs = [[17,2,17],[16,16,5],[14,3,19]]))
print(s.minCost(costs = [[7,6,2]]))
输出:
10
2
2. 粉刷房子 II Paint House-ii
假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。
当然,因为市场上不同颜色油漆的价格不同,所以房子粉刷成不同颜色的花费成本也是不同的。 每个房子粉刷成不同颜色的花费是以一个 n x k 的矩阵来表示的。
例如,costs[0][0] 表示第 0 号房子粉刷成 0 号颜色的成本花费; costs[1][2] 表示第 1 号房子粉刷成 2 号颜色的成本花费,以此类推。 请你计算出粉刷完所有房子最少的花费成本。
示例:
输入:[[1,5,3],[2,9,4]] 输出:5 解释:将 0 号房子粉刷成 0 号颜色,1 号房子粉刷成 2 号颜色。最少花费: 1 + 4 = 5; 或者将 0 号房子粉刷成 2 号颜色,1 号房子粉刷成 0 号颜色。最少花费: 3 + 2 = 5。
进阶:您能否在 O(n*k) 的时间复杂度下解决此问题?
代码:
from typing import List
class Solution:
def minCostII(self, costs: List[List[int]]) -> int:
n = len(costs)
k = len(costs[0])
dp = [[0] * k for _ in range(n+1)]
for i in range(1, n+1):
# 找出前 i-1 个房子中,除第 j 种颜色外的最小花费和次小花费分别是多少
min_cost, sec_min_cost = float('inf'), float('inf')
for j in range(k):
if dp[i-1][j] < min_cost:
sec_min_cost = min_cost
min_cost = dp[i-1][j]
elif dp[i-1][j] < sec_min_cost:
sec_min_cost = dp[i-1][j]
# 根据前面计算的最小花费和次小花费,更新 dp[i][j]
for j in range(k):
if dp[i-1][j] == min_cost:
dp[i][j] = sec_min_cost + costs[i-1][j]
else:
dp[i][j] = min_cost + costs[i-1][j]
return min(dp[n])
# %%
s = Solution()
print(s.minCostII([[1,5,3],[2,9,4]]))
输出:
5
3. 粉刷房子 III Paint House-iii
在一个小城市里,有 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。
示例 2:
输入:houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3 输出:11 解释:有的房子已经被涂色了,在此基础上涂色方案为 [2,2,1,2,2] 此方案包含 target = 3 个街区,分别是 [{2,2}, {1}, {2,2}]。 给第一个和最后一个房子涂色的花费为 (10 + 1) = 11。
示例 3:
输入:houses = [0,0,0,0,0], cost = [[1,10],[10,1],[1,10],[10,1],[1,10]], m = 5, n = 2, target = 5 输出:5
示例 4:
输入:houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3 输出:-1 解释:房子已经被涂色并组成了 4 个街区,分别是 [{3},{1},{2},{3}] ,无法形成 target = 3 个街区。
提示:
m == houses.length == cost.length
n == cost[i].length
1 <= m <= 100
1 <= n <= 20
1 <= target <= m
0 <= houses[i] <= n
1 <= cost[i][j] <= 10^4
代码:
from typing import List
class Solution:
def minCostIII(self, houses: List[int], cost: List[List[int]], m: int, n: int, target: int) -> int:
# i第(几个-1)房子,j第(几个-1)颜色,k组成(几个-1)街区
dp = [[[float('inf') for _ in range(target)] for _ in range(n)] for _ in range(m)]
if houses[0] == 0: # 第一个房子无颜色
for i in range(n): # 初始化第一行
dp[0][i][0] = cost[0][i] # 由于只有一个房子,所以,数量也只能为1,也就是k=0
else: # 有颜色则无法更改,代价也应该为0
dp[0][houses[0] - 1][0] = 0
for i in range(1, m):
for j in range(n):
# 当房子原来有颜色,那么不可改变颜色,只能更新原有颜色与之前颜色的代价,其他颜色跳过
if houses[i] != 0 and houses[i] != j + 1:
continue
for k in range(target):
for loc in range(n):
if loc == j:
# 与前一个房子颜色相同,分块数量一样
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][loc][k])
elif k > 0:
# 与前一个颜色不同,分数数量增加了1
dp[i][j][k] = min(dp[i][j][k], dp[i - 1][loc][k - 1])
# 只有dp[i][j][k]有解且房子无原有颜色,才增加粉刷成本
if dp[i][j][k] != float('inf') and houses[i] == 0:
dp[i][j][k] += cost[i][j]
ans = float('inf')
# 遍历,找到分块为target的最低代价
for j in range(n):
ans = min(ans, dp[m - 1][j][target - 1])
return ans if ans < float('inf') else -1
# %%
s = Solution()
print(s.minCostIII(houses = [0,0,0,0,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3))
print(s.minCostIII(houses = [0,2,1,2,0], cost = [[1,10],[10,1],[10,1],[1,10],[5,1]], m = 5, n = 2, target = 3))
print(s.minCostIII(houses = [0,0,0,0,0], cost = [[1,10],[10,1],[1,10],[10,1],[1,10]], m = 5, n = 2, target = 5))
print(s.minCostIII(houses = [3,1,2,3], cost = [[1,1,1],[1,1,1],[1,1,1],[1,1,1]], m = 4, n = 3, target = 3))
输出:
9
11
5
-1
🌟 每日一练刷题专栏 🌟
✨ 持续,努力奋斗做强刷题搬运工!
👍 点赞,你的认可是我坚持的动力!
🌟 收藏,你的青睐是我努力的方向!
✎ 评论,你的意见是我进步的财富!
☸ 主页:https://hannyang.blog.csdn.net/
Golang每日一练 专栏 | |
Python每日一练 专栏 | |
C/C++每日一练 专栏 | |
Java每日一练 专栏 |