Python每日一练(20230513) 粉刷房子 I\II\III Paint House

简介: Python每日一练(20230513) 粉刷房子 I\II\III Paint House

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


目录
相关文章
|
2月前
|
Python 人工智能
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
64 1
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
|
2月前
|
Shell Unix Linux
Linux 终端命令之文件浏览(3) less
Linux 终端命令之文件浏览(3) less
45 0
Linux 终端命令之文件浏览(3) less
|
2月前
|
Rust
Rust 编程小技巧摘选(8)
Rust 编程小技巧摘选(8)
138 0
Rust 编程小技巧摘选(8)
|
2月前
|
算法 C++ 机器人
力扣 C++|一题多解之动态规划专题(1)
力扣 C++|一题多解之动态规划专题(1)
49 0
力扣 C++|一题多解之动态规划专题(1)
|
2月前
|
C++ Python 索引
Python Numpy入门基础(二)数组操作
Python Numpy入门基础(二)数组操作
37 0
Python Numpy入门基础(二)数组操作
|
2月前
|
C++ 存储
力扣C++|一题多解之数学题专场(1)
力扣C++|一题多解之数学题专场(1)
31 0
力扣C++|一题多解之数学题专场(1)
|
2月前
|
Java Go C++
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
40 0
Golang每日一练(leetDay0118) 扁平化嵌套列表迭代器、整数拆分
|
2月前
|
Java Go C++
Golang每日一练(leetDay0114) 矩阵中的最长递增路径、按要求补齐数组
Golang每日一练(leetDay0114) 矩阵中的最长递增路径、按要求补齐数组
43 0
Golang每日一练(leetDay0114) 矩阵中的最长递增路径、按要求补齐数组
|
2月前
|
Java Go C++
Golang每日一练(leetDay0110) 零钱兑换I\II Coin Change
Golang每日一练(leetDay0110) 零钱兑换I\II Coin Change
54 0
Golang每日一练(leetDay0110) 零钱兑换I\II Coin Change
|
2月前
|
Java Go Rust
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
52 0
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II