【限时免费】20天拿下华为OD笔试之【二分查找】2023B-食堂供餐-100分【闭着眼睛学数理化】全网注释最详细分类最全的华为OD真题题解

【二分查找】2023B-食堂供餐

题目描述与示例

题目描述

某公司员工食堂以盒饭方式供餐。为将员工取餐排队时间降低为0,食堂的供餐速度必须要足够快。现在需要根据以往员工取餐的统计信息,计算出一个刚好能达成排队时间为0的最低供餐速度。即,食堂在每个单位时间内必须至少做出多少份盒饭才能满足要求。

输入

  • 1行为一个正整数N,表示食堂开餐时长。1 <= N <= 1000
  • 2行为一个正整数M,表示开餐前食堂已经准备好的盒饭份数。Pi <= M <= 1000
  • 3行为N个正整数,用空格分隔,依次表示开餐时间内按时间顺序每个单位时间进入食堂取餐的人数Pi
  • 1 <= i <= N0 <= Pi <= 100

输出

一个整数,能满足题目要求的最低供餐速度(每个单位时间需要做出多少份盒饭)。

说明

每人只取一份盒饭。需要满足排队时间为0,必须保证取餐员工到达食堂时,食堂库存盒饭数量不少于本次来取餐的人数。第一个单位时间来取餐的员工只能取开餐前食堂准备好的盒饭。每个单位时间里制作的盒饭只能供应给后续单位时间来的取餐的员工,食堂在每个单位时间里制作的盒饭数量是相同的。

示例一

输入

3
14
10 4 5

输出

3

说明

本样例中,总共有3批员工就餐,每批人数分别为1045

开餐前食堂库存14份。食堂每个单位时间至少要做出3份餐饭才能达成排队时间为0的目标。具体情况如下: 第一个单位时间来的10位员工直接从库存取餐,取餐后库存剩余4份盒饭,加上第一个单位时间做出的3份,库存有7份。

第二个单位时间来的4员工从库存的7份中取4份,取餐后库存剩余3份盒饭,加上第二个单位时间做出的3份,库存有6份。

第三个单位时间来的员工从库存的6份中取5份,库存足够。

如果食堂在单位时间只能做出2份餐饭,则情况如下:

第一个单位时间来的10位员工直接从库存取餐,取餐后库存剩余4份盒饭,加上第一个单位时间做出的2份,库存有6份。 第二个单位时间来的4员工从库存的6份中取4份,取餐后库存剩余2份盒饭,加上第二个单位时间做出的2份,库存有4份。

第三个单位时间来的员工需要取5份,但库存只有4份,库存不够。

解题思路

二段性分析

考虑出餐速度speed能否完成供餐之间的关系

  • 出餐速度speed越大的时候,越可能完成供餐。当取到最值speed = max(nums)时,一定能完成供餐。
  • 对于在区间[1, min(nums)]之间取值的出餐速度speed而言,一定存在一个值ans,使得
    • speed ∈ [0, ans)时,无法完成供餐。
    • speed ∈ [ans, max(nums)]时,可以完成供餐。
    • 这体现了这个问题的二段性ans是我们需要的答案,而ans的寻找就可以用二分查找来完成。

子问题分析

对于二分查找过程中得到的每一个出餐速度speed = mid,我们都要去判断在出餐速度的条件下能否完成供餐

初始化剩余餐数 rest = M,遍历nums数组中每一分钟前来就餐的人数num。若

  • rest < num,则无法完成供餐,直接返回False
  • rest ≥ num,该分钟可以完成供餐,rest要减去当前分钟就餐人数num,同时加上本分钟多提供的餐数speed,用于后续人员的就餐。

上述逻辑整理为代码即构建 check_available(M, nums, speed) 函数

def check_available(M, nums, speed):
    rest = M
    for num in nums:
        if rest < num:
            return False
        rest -= num
        rest += speed
    return True

代码

# 题目:2023B-食堂供餐
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:二分查找
# 代码看不懂的地方,请直接在群上提问



# 该函数用于检查:当选择单位时间出餐份数为 speed 时,能否完成供餐
def check_available(M, nums, speed):
    # 初始化剩余餐数为M
    rest = M
    # 遍历每分钟前来的人数num
    for num in nums:
        # 如果剩余餐数小于本分钟前来人数num
        # 有员工需要等待,无法完成供餐,直接返回False
        if rest < num:
            return False
        # 本分钟可以完成供餐,那么剩余餐数减去就餐人数
        rest -= num
        # 剩余餐数加上该分钟的出餐,可以提供给后续就餐的员工
        rest += speed
    # 在上述循环中没有返回False,说明没有出现员工需要等待的情况
    # 所有人都可以无需等待完成就餐,供餐完成,返回True
    return True


# N分钟
N = int(input())
# 初始已有M份餐
M = int(input())
# N分钟前来就餐的员工数目
nums = list(map(int, input().split()))

# 出餐速度最大值取max(nums),一定能够满足
# 每个员工都不需要等餐就可以就餐
left, right = 1, max(nums) + 1

# 左闭右开区间,退出循环时存在 left = right = mid
# 循环不变量为left < right
while left < right:
    # 计算 left 和 right 的平均值 mid
    mid = (left + right) // 2
    # 可以完成供餐,说明供餐速度较大,可以缩小,搜索区间向左折半、
    # 退出循环时,存在speed = left = right恰好满足check_available(M, nums, speed)
    if check_available(M, nums, mid):
        right = mid
    else:
        left = mid + 1

# 退出循环时,left = right是恰好可以完成供餐的最小速度
print(left)

时空复杂度

时间复杂度:O(NlogC)

  • C = max(nums)为就餐人数数组nums中的最大值。
  • 子问题单次求解即函数check_available(M, nums, speed)时间复杂度为O(N)
  • 二分查找算法的时间复杂度为O(logC))。每次都需要调用check_available()函数,故总的二分查找时间复杂度度为O(NlogC))

空间复杂度:O(1)

华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 OD算法冲刺训练课程表 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值