力扣LeetCode: 2209 用地毯覆盖后的最少白色砖块

news/2025/2/22 23:20:47

题目:

给你一个下标从 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

解法:动态规划

问题分析

我们有一个二进制字符串 floor,表示地板上砖块的颜色:

  • floor[i] = '0' 表示第 i 块砖是黑色。

  • floor[i] = '1' 表示第 i 块砖是白色。

我们有 numCarpets 条黑色地毯,每条地毯的长度为 carpetLen。我们的目标是用这些地毯覆盖尽可能多的白色砖块,使得未被覆盖的白色砖块数量最小。


动态规划思路

动态规划的核心思想是将问题分解为子问题,并通过状态转移方程逐步求解。我们需要定义一个状态,表示在某个位置使用一定数量的地毯时,未被覆盖的白色砖块的最小数量。

1. 定义状态

我们定义 dp[i][j] 表示:

  • 覆盖前 i 块砖块(即 floor[0..i-1])。

  • 使用 j 条地毯。

  • 未被覆盖的白色砖块的最小数量。

2. 状态转移方程

对于每一块砖块 i,我们有两种选择:

  1. 不使用地毯覆盖这块砖块

    • 如果这块砖是白色(floor[i-1] == '1'),则未被覆盖的白色砖块数量增加 1。

    • 状态转移:dp[i][j] = dp[i-1][j] + (floor[i-1] == '1' ? 1 : 0)

  2. 使用地毯覆盖这块砖块

    • 如果使用一条地毯覆盖从第 i-carpetLen 到第 i-1 块砖块,那么未被覆盖的白色砖块数量为 dp[i-carpetLen][j-1]

    • 状态转移:dp[i][j] = dp[i-carpetLen][j-1]

我们需要在这两种选择中取最小值:

dp[i][j] = min(
    dp[i-1][j] + (floor[i-1] == '1' ? 1 : 0),  // 不使用地毯
    dp[i-carpetLen][j-1]                       // 使用地毯
);
3. 初始化
  • 当没有砖块时i = 0):

    • 无论有多少地毯,未被覆盖的白色砖块数量都是 0。

    • dp[0][j] = 0,其中 0 <= j <= numCarpets

  • 当没有地毯时j = 0):

    • 未被覆盖的白色砖块数量就是前 i 块砖中白色砖块的总数。

    • dp[i][0] = dp[i-1][0] + (floor[i-1] == '1' ? 1 : 0)

4. 最终结果

我们需要计算 dp[n][numCarpets],其中 n 是砖块的总数。这表示覆盖所有砖块并使用所有地毯后,未被覆盖的白色砖块的最小数量。


代码实现

以下是完整的代码实现:

class Solution {
public:
    int minimumWhiteTiles(string floor, int numCarpets, int carpetLen) {
        int n = floor.length();
        // DP 表:dp[i][j] 表示前 i 块砖,使用 j 条地毯时,未被覆盖的白色砖块的最小数量
        vector<vector<int>> dp(n + 1, vector<int>(numCarpets + 1, 0));

        // 初始化:当没有地毯时,未被覆盖的白色砖块数量
        for (int i = 1; i <= n; ++i) {
            dp[i][0] = dp[i-1][0] + (floor[i-1] == '1' ? 1 : 0);
        }

        // 填充 DP 表
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= numCarpets; ++j) {
                // 选择 1:不使用地毯覆盖第 i 块砖
                int option1 = dp[i-1][j] + (floor[i-1] == '1' ? 1 : 0);

                // 选择 2:使用地毯覆盖第 i 块砖
                int option2 = (i >= carpetLen) ? dp[i-carpetLen][j-1] : 0;

                // 取最小值
                dp[i][j] = min(option1, option2);
            }
        }

        // 返回结果
        return dp[n][numCarpets];
    }
};

示例解释

示例 1:

输入:floor = "10110101"numCarpets = 2carpetLen = 2

  1. 初始化

    • dp[i][0] 表示不使用地毯时,前 i 块砖中白色砖块的数量。

    • 例如,dp[8][0] = 5(因为有 5 块白色砖块)。

  2. 填充 DP 表

    • 对于每块砖,尝试使用或不使用地毯,选择最优解。

    • 最终 dp[8][2] = 2,表示使用 2 条地毯后,未被覆盖的白色砖块数量为 2。

示例 2:

输入:floor = "11111"numCarpets = 2carpetLen = 3

  1. 初始化

    • dp[i][0] 表示不使用地毯时,前 i 块砖中白色砖块的数量。

    • 例如,dp[5][0] = 5(因为有 5 块白色砖块)。

  2. 填充 DP 表

    • 使用 2 条长度为 3 的地毯,可以覆盖所有白色砖块。

    • 最终 dp[5][2] = 0,表示所有白色砖块都被覆盖。


复杂度分析

  • 时间复杂度O(n * numCarpets),其中 n 是砖块的数量。

  • 空间复杂度O(n * numCarpets),用于存储 DP 表。


总结


http://www.niftyadmin.cn/n/5862839.html

相关文章

go 错误处理 error

普通错误处理 // 包路径 package mainimport ("errors""fmt" )func sqrt(f1, f2 float64) (float64, error) {if f2 < 0 {return 0, errors.New("error: f2 < 0")}return f1 / f2, nil }func sqrt1(f1, f2 float64) {if re, err : sqrt(f…

Python中的Flask深入认知搭建前端页面?

一、Flask 的介绍 1. 什么是Flask&#xff1f; Flask 是一个轻量级的 Python Web 框架&#xff0c;因其简单易用、灵活性高而广受欢迎。它适合快速开发小型应用&#xff0c;也可以通过扩展支持复杂的功能需求。可以结合 HTML、CSS 和 JavaScript 实现丰富的交互功能。 2. 核…

【C# 数据结构】队列 FIFO

目录 队列的概念FIFO (First-In, First-Out)Queue<T> 的工作原理&#xff1a;示例&#xff1a;解释&#xff1a; 小结&#xff1a; 环形队列1. **FIFO&#xff1f;**2. **环形缓冲队列如何实现FIFO&#xff1f;**关键概念&#xff1a; 3. **环形缓冲队列的工作过程**假设…

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-split_dota.py

split_dota.py ultralytics\data\split_dota.py 目录 split_dota.py 1.所需的库和模块 2.def bbox_iof(polygon1, bbox2, eps1e-6): 3.def load_yolo_dota(data_root, split"train"): 4.def get_windows(im_size, crop_sizes(1024,), gaps(200,), im_rate_t…

中文Build a Large Language Model (From Scratch) 免费获取全文

中文pdf下载地址&#xff1a;https://pan.baidu.com/s/1aq2aBcWt9vYagT2-HuxdWA?pwdlshj 提取码&#xff1a;lshj 原文、代码、视频项目地址&#xff1a;https://github.com/rasbt/LLMs-from-scratch 翻译工具&#xff1a;沉浸式翻译&#xff08;https://app.immersivetrans…

智能合约的部署

https://blog.csdn.net/qq_40261606/article/details/123249473 编译 点击图中的 “Compile 1_Storage.sol” 存和取一个数的合约&#xff0c;remix自带 pragma solidity >0.8.2 <0.9.0; /*** title Storage* dev Store & retrieve value in a variable* custom:d…

输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路

详细前端代码写于上一篇&#xff1a;输入搜索、分组展示选项、下拉选取&#xff0c;el-select 实现&#xff1a;即输入关键字检索&#xff0c;返回分组选项&#xff0c;选取跳转到相应内容页 —— VUE项目-全局模糊检索 【效果图】&#xff1a;分组展示选项 >【去界面操作体…

在工作中PostgreSQL常用的SQL命令

1. 查看所有数据库 \l 或 SELECT datname FROM pg_database; 2. 查看当前数据库中的所有表 \dt 或 SELECT table_name FROM information_schema.tables WHERE table_schema public; 3. 查看所有表空间 \db 或 SELECT spcname FROM pg_tablespace; 4. 查看所有用户&…