二分查找解力扣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天。

参考来源

相关推荐
学计算机的计算基1 小时前
二叉树算法下篇:递归核心技巧与高频面试题详解
java·笔记·算法
WZF-Sang1 小时前
TCP和UDP协议
linux·服务器·网络·c++·学习·tcp/ip·udp
Tim_101 小时前
【C++】014、左值与右值的区别
开发语言·c++
想人陪的玫瑰1 小时前
winform 能用 Native AOT 吗?——TDS 项目的实战尝试
c++·mfc
水龙吟啸1 小时前
华为2026.6.24机考选择题+编程题【速刷敲黑板】
人工智能·深度学习·算法·机器学习·华为
天空'之城1 小时前
Linux 系统编程 14:Reactor 反应堆模式
linux·开发语言·网络编程·reactor 反应堆模式
Eloudy1 小时前
全文 - Evolution Strategies as a Scalable Alternative to Reinforcement Learning
人工智能·算法
Zhou1411362 小时前
Java常见面试题7
java·开发语言
^yi2 小时前
【C++】类和对象(全)
开发语言·c++