1. 问题描述:
给你一个下标从 0 开始的 二进制 字符串 floor ,它表示地板上砖块的颜色。
floor[i] = '0' 表示地板上第 i 块砖块的颜色是黑色 。
floor[i] = '1' 表示地板上第 i 块砖块的颜色是白色 。
同时给你 numCarpets 和 carpetLen 。你有 numCarpets 条黑色的地毯,每一条黑色的地毯长度都为 carpetLen 块砖块。请你使用这些地毯去覆盖砖块,使得未被覆盖的剩余白色砖块的数目最小 。地毯相互之间可以覆盖。请你返回没被覆盖的白色砖块的最少数目。
示例 1:
输入:floor = "10110101", numCarpets = 2, carpetLen = 2
输出:2
解释:
上图展示了剩余 2 块白色砖块的方案。
没有其他方案可以使未被覆盖的白色砖块少于 2 块。
示例 2:
输入:floor = "11111", numCarpets = 2, carpetLen = 3
输出:0
解释:
上图展示了所有白色砖块都被覆盖的一种方案。
注意,地毯相互之间可以覆盖。
提示:
1 <= carpetLen <= floor.length <= 1000
floor[i] 要么是 '0' ,要么是 '1' 。
1 <= numCarpets <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-white-tiles-after-covering-with-carpets/
2. 思路分析:
分析题目可以知道直接做不好做,对于这种直接做不好做而且数据范围在几千之内的题目我们考虑能否使用dp或者贪心来解决,感觉应该可以使用dp来解决,所以尝试dp来解决,dp的两个核心点是状态定义和状态计算,一般状态定义是结合题目中给出的相关变量声明对应维度的数组或者列表,由题目可知题目有两个值:地毯长度和地毯的个数,可以发现声明两维才可以在体现这两个变量的变化过程后面才可以进行状态之间的转移,其中f[i][j]表示用i条地毯去覆盖前j块地板,没被地毯覆盖的白色砖块的最少数目,在状态计算中一般是找最后一个不同点,我们可以考虑能否用第i条地毯的末尾覆盖第j块地板,注意是"末尾"这样使得尽可能覆盖更多的砖块:
- 不覆盖第j块地板,f[i][j] = f[i][j - 1] + floor[j] == "1"
- 覆盖,f[i][j] = f[i - 1][j - carpetLen]
上面两种情况取一个min即可,最终f[n][m - 1]就是答案,n为地毯的数目,m为地板的长度。
3. 代码如下:
class Solution:
# f列表的状态定义是什么
def minimumWhiteTiles(self, floor: str, numCarpets: int, carpetLen: int) -> int:
m, n = len(floor), numCarpets
f = [[0] * (m + 10) for i in range(n + 10)]
# 对于i = 0的时候不能覆盖只能够单独计算
f[0][0] = int(floor[0])
for i in range(1, m):
f[0][i] = f[0][i - 1] + int(floor[i])
for i in range(1, n + 1):
for j in range(carpetLen, m):
f[i][j] = min(f[i][j - 1] + int(floor[j]), f[i - 1][j - carpetLen])
return f[n][m - 1]