C++二分查找算法的应用:长度递增组的最大数目

本文涉及的基础知识点

二分查找

题目

给你一个下标从 0 开始、长度为 n 的数组 usageLimits 。

你的任务是使用从 0 到 n - 1 的数字创建若干组,并确保每个数字 i 在 所有组 中使用的次数总共不超过 usageLimitsi 次。此外,还必须满足以下条件:

每个组必须由 不同 的数字组成,也就是说,单个组内不能存在重复的数字。

每个组(除了第一个)的长度必须 严格大于 前一个组。

在满足所有条件的情况下,以整数形式返回可以创建的最大组数。

示例 1:

输入:usageLimits = 1,2,5

输出:3

解释:在这个示例中,我们可以使用 0 至多一次,使用 1 至多 2 次,使用 2 至多 5 次。

一种既能满足所有条件,又能创建最多组的方式是:

组 1 包含数字 2

组 2 包含数字 1,2

组 3 包含数字 0,1,2

可以证明能够创建的最大组数是 3 。

所以,输出是 3 。

示例 2:

输入:usageLimits = 2,1,2

输出:2

解释:在这个示例中,我们可以使用 0 至多 2 次,使用 1 至多 1 次,使用 2 至多 2 次。

一种既能满足所有条件,又能创建最多组的方式是:

组 1 包含数字 0

组 2 包含数字 1,2

可以证明能够创建的最大组数是 2 。

所以,输出是 2 。

示例 3:

输入:usageLimits = 1,1

输出:1

解释:在这个示例中,我们可以使用 0 和 1 至多 1 次。

一种既能满足所有条件,又能创建最多组的方式是:

组 1 包含数字 0

可以证明能够创建的最大组数是 1 。

所以,输出是 1 。
参数范围

1 <= usageLimits.length <= 105

1 <= usageLimitsi <= 109

分析

知识点

假定最长组数为len,则各组长度一定是1,2...len。假定各组长度不是连续的,缺少x,那么将(x...) 都扔掉一个元素,变成[x,...)。持续这个过程至到各组长度连续为至。

只关心各值的数量,不关心值,比如:1,2,3和2,1,3完全相同。故可对数据进行排序。

二分

如果如果能创建n组,则一定能创建n-1组。随着len增加,一定会由能创建变成不能创建。寻找最后一个能创建的len。显然适合用左闭右开的二分。

判断能否创建len组

预处理

目标数组为{1,2...len},源数组为升序排序后的 usageLimits,长度不足则在前面补0。比如:目标数组{1,2,3},源数组{0,3,3};目标数组{0,1,2,3},{1,1,2,2}。

推理

我们用len数组表示目标数组,leni的含义,0,len\[i)都会有此元素。

leni==usageLimitsi 刚好
leni > usageLimitsi 不足,需要补缺
leni < usageLimitsi 多余,可以用于补缺

长度为3

由于组内不能有重复元素,所以超过len个元素是无效的。我们用表格分析,那些情况刚好创建3组,没多余的数字。

1,1,1,1,1,1 可以 1填2和3的空缺
1,1,1,1,2 可以 1填2和3的空缺
1,1,2,2 可以 1填3的空缺
2,2,2 可以 2填3的空缺
1,1,1,3 可以 1填2的空缺
1,2,3 可以 不用填空缺
3,3 不可以 1的空缺无法填

猜测

3可以填4及以上缺,如:1333,{2},{3,4},{2,3,4},{1,2,3,4}

如何补缺

假定i1<i2,i2无法补i1的缺,因为i2已经用于[0,i2)不能用于[0,i1)中的任何组。

i1可以补i2的缺。i1只由于[0,i1)组,所以补[i2,...)的缺,不会造成同一组有重复数据。

一个数不会补缺两次

假定k = leni2 -eni1,则i1多余不会超过k,

usageLimitsi1-leni1 >k

==>usageLimitsi1 >leni1+k

==>usageLimitsi1 >leni2

因为usageLimitsi2>=usageLimitsi1

所以:usageLimitsi2>len2

所以:i2有多余,和有缺矛盾。

i1多余不会超过k,所以补完i2的缺就空了。

==>无需考虑一个数补两个缺

代码

核心代码

class Solution {

public:

int maxIncreasingGroups(vector& usageLimits) {

m_c = usageLimits.size();

m_v = usageLimits;

sort(m_v.begin(), m_v.end());

int left = 1, right = m_c + 1;

while (right - left > 1)

{

const int mid = left + (right - left) / 2;

if (Can(mid))

{

left = mid;

}

else

{

right = mid;

}

}

return left;

}

bool Can(int len)

{

int i = m_c - 1;

long long llNeed = 0;

for (; len > 0; len--,i--)

{

llNeed -= (m_vi - len);

if (m_vi >= len)

{

llNeed = max(0LL, llNeed);

}

}

for(;i >= 0 ; i--)

{

llNeed -= m_vi;

}

return llNeed <= 0;

}

int m_c;

vector m_v;

};

测试用例

template

void Assert(const T& t1, const T& t2)

{

assert(t1 == t2);

}

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(v1i ,v2i);

}

}

int main()

{

Solution slu;

vector usageLimits;

int res = 0;

usageLimits = { 2,2,2 };

res = slu.maxIncreasingGroups(usageLimits);

Assert(res, 3);

usageLimits = { 1,2,5 };

res = slu.maxIncreasingGroups(usageLimits);

Assert(res, 3);

usageLimits = { 2,1,2 };

res = slu.maxIncreasingGroups(usageLimits);

Assert(res, 2);

usageLimits = { 1,1 };

res = slu.maxIncreasingGroups(usageLimits);

Assert(res, 1);

复制代码
//CConsole::Out(res);

}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步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

相关推荐
随意起个昵称10 小时前
区间dp-基础题目1(石子合并)
算法·动态规划
吞下星星的少年·-·11 小时前
线段树模板
算法
星空椰11 小时前
Python 面向对象高级:继承与类定义详解
开发语言·python
wunaiqiezixin11 小时前
如何在C++中创建和管理线程
c++
段一凡-华北理工大学11 小时前
2026 高炉炼铁智能化技术全景与演进路径~系列文章11:演进路径与行业未来
大数据·网络·人工智能·算法·工业智能体·高炉炼铁智能化
白露与泡影11 小时前
2026大厂Java面试题大全!牛客网最新版
java·开发语言
凯瑟琳.奥古斯特11 小时前
高阶子查询题目精炼
开发语言·数据库·python·职场和发展·数据库开发
雪度娃娃11 小时前
转向现代C++——在意为改写的函数添加 override
开发语言·c++
王老师青少年编程11 小时前
csp信奥赛C++高频考点专项训练之前缀和&差分 --【一维差分】:[NOIP 2018 提高组] 铺设道路
c++·前缀和·差分·csp·高频考点·信奥赛·铺设道路
叶小鸡12 小时前
小鸡玩算法-力扣HOT100-多维动态规划
算法·leetcode·动态规划