C++前缀和算法的应用:用地毯覆盖后的最少白色砖块 原理源码测试用例

简介: C++前缀和算法的应用:用地毯覆盖后的最少白色砖块 原理源码测试用例

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

题目

给你一个下标从 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.length 小于carpetLen,否则一定可以覆盖。这种情况题目已经排除了。

计算最多可以盖住多少块白砖,白砖数减去盖住的白砖,就是未盖住的白砖数。

假定新毯子覆盖在[iPre,iPre + carpetLen),那么前一张毯子不一定在[iPre-carpetLen,iPre),可以更前。所以执行:

dp[i + 1] = max(dp[i], dp[i + 1]);

执行之前:dp[i]的含义是i的最后一张毯子的尾部,可以覆盖最多砖瓦数。

执行之后:dp[i]的含义是的最后一张毯子的尾部<=i,可以覆盖最多砖瓦数。

时间复杂度

O(n*n)。两层循环,第一层,枚举第i张毛毯。第二层循环,枚举上一次的覆盖位置。

步骤

一,计算白砖数量的前缀和。

二,两层循环。

## 变量解释

vSum vSum[i]表示 floor[0,i)中白砖的数量,也就是前i块砖中,白砖的数量
pre 表示i块毯子,覆盖了[0,i),能盖住的最多白砖数

代码

核心代码

class Solution {
public:
int minimumWhiteTiles(string floor, int numCarpets, int carpetLen) {
//错误想法:如果盖毯子,则毯子的末端一定盖住白砖
//计算最多可以盖住多少块白砖
vector vSum = { 0 };//vSum[i]表示 floor[0,i)中白砖的数量
for (const char& ch : floor)
{
vSum.emplace_back(vSum.back() + (‘1’ == ch));
}
m_c = floor.length();
vector pre (m_c+1,0);//表示i块毯子,覆盖了[0,i),能盖住的最多白砖数
for (int i = 0; i < numCarpets; i++)
{
vector dp = pre;
for (int iPre = 0; iPre < pre.size(); iPre++)
{
const int iNew = min(m_c , iPre + carpetLen);
dp[iNew] = max(dp[iNew], pre[iPre] + (vSum[iNew]-vSum[iPre]));
}
for (int i = 0; i < m_c; i++)
{
dp[i + 1] = max(dp[i], dp[i + 1]);
}
pre.swap(dp);
}
return vSum.back() - *std::max_element(pre.begin(),pre.end());
}
int m_c;
};

测试用例

template
void Assert(const vector& v1, const vector& v2)
{
if (v1.size() != v2.size())
{
assert(false);
return;
}
for (int i = 0; i < v1.size(); i++)
{
assert(v1[i] == v2[i]);
}
}
template
void Assert(const T& t1, const T& t2)
{
assert(t1 == t2);
}
int main()
{
Solution slu;
string floor = “10110101”;
int numCarpets = 2, carpetLen = 2;
int res;
floor = "1110111";
numCarpets = 2, carpetLen = 3;
res = slu.minimumWhiteTiles(floor, numCarpets, carpetLen);
Assert(0, res);
floor = "10110101";
numCarpets = 2, carpetLen = 2;
res = slu.minimumWhiteTiles(floor, numCarpets, carpetLen);
Assert(2, res);
floor = "11111";
numCarpets = 2, carpetLen = 3;
res = slu.minimumWhiteTiles(floor, numCarpets, carpetLen);
Assert(0, res); 
//CConsole::Out(res);

}

2023年2月旧代码

class Solution {
public:
int minimumWhiteTiles(const string floor, const int numCarpets, const int carpetLen) {
m_c = floor.length();
//dp[i][j] 已经处理了i块砖,用了j块地毯,最少为覆盖的砖数
vector<vector> dp(m_c+1, vector(numCarpets+1,INT_MAX));
dp[0][0] = 0;
for (int brick = 0; brick < m_c; brick++)
{
for (int iUseCarpets = 0; iUseCarpets <= numCarpets; iUseCarpets++)
{
const int& iValue = dp[brick][iUseCarpets];
if (INT_MAX == iValue)
{
continue;
}
//空一格
dp[brick + 1][iUseCarpets] = min(dp[brick + 1][iUseCarpets], iValue + (‘1’ == floor[brick]));
//假定不重叠,如果重叠右移到不重叠,不影响结果
if (numCarpets == iUseCarpets)
{
continue;
}
const int iNewBrick = min(brick + carpetLen, m_c);
dp[iNewBrick][iUseCarpets + 1] = min(dp[iNewBrick][iUseCarpets + 1], iValue);
}
}
return *std::min_element(dp[m_c].begin(), dp[m_c].end());
}
int m_c;
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

| 鄙人想对大家说的话

|

|-|

|闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。|

| 墨家名称的来源:有所得以墨记之。 |

|如果程序是一条龙,那算法就是他的是睛|

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境:

VS2022 C++17

相关文章
|
2月前
|
监控 安全 Shell
管道符在渗透测试与网络安全中的全面应用指南
管道符是渗透测试与网络安全中的关键工具,既可用于高效系统管理,也可能被攻击者利用实施命令注入、权限提升、数据外泄等攻击。本文全面解析管道符的基础原理、实战应用与防御策略,涵盖Windows与Linux系统差异、攻击技术示例及检测手段,帮助安全人员掌握其利用方式与防护措施,提升系统安全性。
142 6
|
13天前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
57 11
|
1月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
374 11
|
2月前
|
机器学习/深度学习 存储 分布式计算
Java 大视界 --Java 大数据机器学习模型在金融风险压力测试中的应用与验证(211)
本文探讨了Java大数据与机器学习模型在金融风险压力测试中的创新应用。通过多源数据采集、模型构建与优化,结合随机森林、LSTM等算法,实现信用风险动态评估、市场极端场景模拟与操作风险预警。案例分析展示了花旗银行与蚂蚁集团的智能风控实践,验证了技术在提升风险识别效率与降低金融风险损失方面的显著成效。
|
2月前
|
人工智能 IDE 测试技术
Browser-Use在UI自动化测试中的应用
Browser-Use是一款浏览器自动化工具,具备视觉与HTML解析、多标签管理、操作记录与复现、自定义操作、自我纠正及并行执行等功能,助力AI智能体高效完成网页任务。
248 0
|
5月前
|
测试技术 数据库 Python
解释测试中setup和teardown函数的应用。
总结起来,`setup`和 `teardown`函数就像扔宴会的主人,他们保障了宴会的流畅进行。他们是准备环境和清理现场的重要工作人员,他们的工作直接影响着我们的测试效率和质量。我们可以把 `setup`和 `teardown`想象成隐藏在幕后,默默为我们服务的工作者,他们做着我们需要但是往往忽视的工作。所以,下次当你写测试的时候,别忘了给你的 `setup`和 `teardown`留出足够的位置,因为他们的作用可能是你成功的保证。
127 14
|
5月前
|
存储 5G 测试技术
时钟同步测试校验仪的应用介绍
时间同步测试仪是一种高精度、高可靠性的设备,用于测量和评估时间同步系统的性能。它广泛应用于电力系统(如电网调度、继电保护)、通信网络(如5G基站、光传输网络)、铁路交通(如列车运行控制、信号系统)、工业自动化(如生产线、控制系统)以及科学研究(如天文观测、粒子物理实验)等领域。其功能包括高精度时间测量、多信号接口支持、自动测量与分析、数据存储导出及性能评估输出,确保各领域设备间的时间同步精度与稳定性,保障系统高效运行。
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
116 0
|
4月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
191 0