二分查找解力扣1011最优运载能力

问题解析 :力扣1011 题 "在 D 天内送达包裹的能力" 要求确定在给定天数 D 内,将所有包裹从传送带上运完的最低运载能力 。运载能力 capacity 表示船每天能运送的最大重量,且必须按数组顺序运送,每天运送的总重量不能超过 capacity

核心思路 :这是一个二分查找 问题。运载能力 capacity 存在一个可行域

  • 下界 left:至少需要能运走最重的单个包裹,即 max(weights)
  • 上界 right:最坏情况一天运完所有包裹,即 sum(weights)
    [left, right] 范围内,对于任意一个 capacity,我们可以通过模拟运送过程计算出所需天数 needDays。根据 needDaysD 的关系来调整二分查找的边界:
    *若 needDays <= D,说明当前运力充足或刚好,可以尝试减小运力(缩小右边界)。
  • needDays > D,说明当前运力不足,必须增大运力(增大左边界)。
    最终,left 即为所求的最小运力。

C++ 代码实现

cpp 复制代码
class Solution {
public:
    int shipWithinDays(vector<int>& weights, int D) {
        // 确定二分查找的左右边界 int left = *max_element(weights.begin(), weights.end()); // 运力至少能装下最重的包裹 int right = accumulate(weights.begin(), weights.end(), 0); // 运力最多一天运完所有        while (left < right) {
            int mid = left + (right - left) / 2; // 当前尝试的运力 int need = 1; // 需要运送的天数,初始为1天
            int cur = 0;  // 当前这一天已经装载的重量
            // 模拟以 mid 为运力,运送所有包裹所需的天数 for (int weight : weights) {
                if (cur + weight > mid) { // 如果加上当前包裹会超载
                    ++need; // 则需要新的一天
                    cur = weight;         // 新的一天从当前包裹开始装
                } else {
                    cur += weight;        // 没超载,继续装
                }
            }
            // 根据所需天数调整二分边界 if (need <= D) {
                right = mid; // 运力足够或有余,尝试更小的运力
            } else {
                left = mid + 1; // 运力不足,必须增大            }
        }
        return left; // 此时 left == right,即为最小运力 }
};

代码说明

  1. 边界初始化left 初始化为数组最大值,right 初始化为数组总和 。
  2. 二分查找循环 :当 left < right 时,计算中间值 mid 作为尝试的运力。
  3. 模拟运送函数(内嵌循环) :遍历所有包裹,累加当前天的重量 cur。若加上当前包裹后重量超过 mid,则天数 need 加一,并在新的一天开始运送该包裹 。
  4. 边界调整
    • 若计算出的所需天数 need 小于等于 D,说明运力 mid 可行,为了寻找最小 运力,将搜索范围缩小至左半部分 (right = mid)。
    • need 大于 D,说明运力 mid 不足,需增大运力,将搜索范围调整至右半部分 (left = mid + 1)。
  5. 返回值 :循环结束时 leftright 相等,即为满足条件的最小运力。
  6. 复杂度分析
    • 时间复杂度:O(n log m),其中 n 是包裹数量,m 是包裹总重量。二分查找复杂度为 O(log m),每次模拟运送需要 O(n)。
    • 空间复杂度:O(1),只使用了常数个额外变量。

示例

输入:weights = [1,2,3,4,5,6,7,8,9,10], D = 5

  1. left = 10, right = 55
  2. 第一次尝试 mid = (10+55)/2 = 32,模拟运送:[1,2,3,4,5,6,7,8] (36>32,分两天),[9,10],共需 3 天 (need=3)。 3 <= 5,所以 right = 32
  3. 继续二分,最终找到最小运力为 15。验证:以运力15运送,[1,2,3,4,5], [6,7], [8], [9], [10] 正好需要5天。

参考来源

相关推荐
choumin16 小时前
创建型模式——工厂方法模式
c++·设计模式·工厂方法模式·创建型模式
云小逸16 小时前
【SVN 详细使用指南:从入门到团队协作】
c++·svn
互联网中的一颗神经元17 小时前
小白python入门 - 39. 采集流水线小项目
开发语言·python
徐小夕17 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
Wang's Blog17 小时前
Go-Zero 项目开发22:用户群聊功能的实现与完善
开发语言·golang
a11177618 小时前
坦克大战3D Three.js 3D (开源项目)
开发语言·javascript·3d
可编程芯片开发19 小时前
UPFC统一潮流控制器的simulink建模与仿真
算法
小小仙子19 小时前
矢量网络分析仪如何测试S参数的?
人工智能·算法·机器学习
Wang's Blog20 小时前
Go-Zero项目开发24: 基于Bitmap实现群聊消息已读未读
开发语言·后端·golang