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

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

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

  • 下界 left:至少需要能运走最重的单个包裹,即 max(weights)。
  • 上界 right:最坏情况一天运完所有包裹,即 sum(weights)。
    在 [left, right] 范围内,对于任意一个 capacity,我们可以通过模拟运送过程计算出所需天数 needDays。根据 needDays 与 D 的关系来调整二分查找的边界:
    *若 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. 返回值 :循环结束时 left 和 right 相等,即为满足条件的最小运力。
  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天。

参考来源

相关推荐
Pniubi1 分钟前
HashMap扩容全流程
java·开发语言·数据结构
白杨尚青2 小时前
C++进阶篇(二):多态——虚函数、重写、虚函数表与三个经典坑(附完整代码仓库)
开发语言·c++·多态·虚函数·重写·动态绑定
syagain_zsx2 小时前
spdlog实战:日志分级、滚动与性能调优
linux·c++·日志库·二次开发日志库
zyl76516 小时前
FlashAttention 详解:从 GPU 硬件、普通 Attention 到分块计算与 Online Softmax
算法
爱读书的小胖20 小时前
LeetCode 122:买卖股票的最佳时机 II(C)解题分析
算法
结局无敌20 小时前
React Native for OpenHarmony 实战:三方库 react-native-modal-dialog 的鸿蒙化适配指南
深度学习·算法·react native·react.js·harmonyos
WJ.Polar20 小时前
Java封装、继承、多态
java·开发语言
摇滚侠20 小时前
Java 中如何表示负数,有符号和无符号的区别,补码的计算规则,char byte short int long 的范围
java·开发语言
ychqsq20 小时前
234.无题
经验分享·职场和发展
OPEN-F20 小时前
ROS2系列教程:上位机建图与导航(原理综合)
算法·机器人