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

参考来源

相关推荐
chenbingjie_c43 分钟前
C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池
开发语言·c++
专注仿真1 小时前
ACM算法
算法·深度优先
Escalating_xu2 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言
实心儿儿2 小时前
Qt — Qt 事件
开发语言·qt
周杰偷奶茶2 小时前
【Java】数据类型与变量
java·开发语言
code斗2 小时前
Java数据结构:堆详解
java·开发语言·数据结构
Frank_refuel3 小时前
【C++】Json库介绍和使用
c++
重生之小比特3 小时前
【C++进阶】map和set
java·开发语言·c++
lie..3 小时前
30天从零开始学AI应用开发(Day 12):像产品一样稳:流式输出、报错重试、花钱控制
开发语言·人工智能·php
傻啦嘿哟3 小时前
Python的默认参数把我坑惨了,原来写[]和写None的区别这么大
开发语言·python·机器学习