• C++前缀和算法的应用:装包裹的最小浪费空间 原理源码测试用例


    本文涉及的基础知识点

    C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

    LeetCode1889装包裹的最小浪费空间

    给你 n 个包裹,你需要把它们装在箱子里,每个箱子装一个包裹。总共有 m 个供应商提供 不同尺寸 的箱子(每个规格都有无数个箱子)。如果一个包裹的尺寸 小于等于 一个箱子的尺寸,那么这个包裹就可以放入这个箱子之中。
    包裹的尺寸用一个整数数组 packages 表示,其中 packages[i] 是第 i 个包裹的尺寸。供应商用二维数组 boxes 表示,其中 boxes[j] 是第 j 个供应商提供的所有箱子尺寸的数组。
    你想要选择 一个供应商 并只使用该供应商提供的箱子,使得 总浪费空间最小 。对于每个装了包裹的箱子,我们定义 浪费的 空间等于 箱子的尺寸 - 包裹的尺寸 。总浪费空间 为 所有 箱子中浪费空间的总和。
    比方说,如果你想要用尺寸数组为 [4,8] 的箱子装下尺寸为 [2,3,5] 的包裹,你可以将尺寸为 2 和 3 的两个包裹装入两个尺寸为 4 的箱子中,同时把尺寸为 5 的包裹装入尺寸为 8 的箱子中。总浪费空间为 (4-2) + (4-3) + (8-5) = 6 。
    请你选择 最优 箱子供应商,使得 总浪费空间最小 。如果 无法 将所有包裹放入箱子中,请你返回 -1 。由于答案可能会 很大 ,请返回它对 109 + 7 取余 的结果。
    示例 1:
    输入:packages = [2,3,5], boxes = [[4,8],[2,8]]
    输出:6
    解释:选择第一个供应商最优,用两个尺寸为 4 的箱子和一个尺寸为 8 的箱子。
    总浪费空间为 (4-2) + (4-3) + (8-5) = 6 。
    示例 2:
    输入:packages = [2,3,5], boxes = [[1,4],[2,3],[3,4]]
    输出:-1
    解释:没有箱子能装下尺寸为 5 的包裹。
    示例 3:
    输入:packages = [3,5,8,10,11,12], boxes = [[12],[11,9],[10,5,14]]
    输出:9
    解释:选择第三个供应商最优,用两个尺寸为 5 的箱子,两个尺寸为 10 的箱子和两个尺寸为 14 的箱子。
    总浪费空间为 (5-3) + (5-5) + (10-8) + (10-10) + (14-11) + (14-12) = 9 。

    参数范围
    n == packages.length
    m == boxes.length
    1 <= n <= 105
    1 <= m <= 105
    1 <= packages[i] <= 105
    1 <= boxes[j].length <= 105
    1 <= boxes[j][k] <= 105
    sum(boxes[j].length) <= 105
    boxes[j] 中的元素 互不相同 。

    分析

    思路

    用v代表某个商人所有的箱子,按升序排序。v[0]尺寸的箱子装所有尺寸小于等于v[0]的包括,就是v[0]箱子的数量等于,尺寸为[0,v[0]]箱子的数量。同理v[1]的数量等于尺寸为(v[0],v[1]]包裹的数量。

    注意

    如果商人最大号的箱子小于最大号包裹,则不能选择此商人。如果所有商人都不能选择,则返回-1。如果多个箱子大于最大号的包裹,这些箱子中只有第一个有用。
    用前缀和计算包裹的数量,小心索引溢出。

    变量含义

    iMax最大号包裹尺寸
    vSumvSum[i] 等于 空间小于等于i 的包裹数量
    llNeed所有包裹的总空间
    cur当前商人提供的箱子的总空间

    代码

    核心代码

    class Solution {
    public:
    int minWastedSpace(vector& packages, vector& boxes) {
    int iMax = *std::max_element(packages.begin(), packages.end());
    vector vNum(iMax + 1);
    long long llNeed = 0;
    for (const auto& n : packages)
    {
    vNum[n]++;
    llNeed += n;
    }
    vector vSum = { 0 };//vSum[i] 等于 空间小于等于i 的包裹数量
    for (int i = 1; i <= iMax; i++)
    {
    vSum.emplace_back(vSum.back() + vNum[i]);
    }
    long long llHas = LLONG_MAX;
    for (auto& v : boxes)
    {
    sort(v.begin(), v.end());
    if (v.back() < iMax)
    {
    continue;
    }
    int pre = 0;
    long long cur = 0;//当前空间上提供的包裹的总容量
    for ( auto& n : v)
    {
    cur += ((long long)vSum[min(n,iMax)] - vSum[pre]) * n;
    pre = n;
    if (n >= iMax)
    {
    break;
    }
    }
    llHas = min(llHas, cur);
    }
    if (LLONG_MAX == llHas)
    {
    return -1;
    }
    const long long llMod = 1e9 + 7;
    return (llHas - llNeed) % llMod;
    }
    };

    测试用例

    template
    void Assert(const vector& v1, const vector& v2)
    {
    if (v1.size() != v2.size())
    {
    assert(false);
    return;
    }
    for (int i = 0; i < v1.size(); i++)
    {
    assert(v1[i] == v2[i]);
    }
    }

    template
    void Assert(const T& t1, const T& t2)
    {
    assert(t1 == t2);
    }

    int main()
    {
    Solution slu;
    vector packages;
    vectorboxes;
    int res = 0;
    packages = { 3,5,8,10,11,12 };
    boxes = { {12},{11,9},{10,5,14} };
    res = slu.minWastedSpace(packages, boxes);
    Assert(9, res);
    packages = { 3, 5, 8, 7, 5, 8, 10, 11, 12 };
    boxes = { {12},{11,9},{10,5,14} };
    res = slu.minWastedSpace(packages, boxes);
    Assert(14, res);
    packages = { 2,3,5 };
    boxes = { {4,8},{2,8} };
    res = slu.minWastedSpace(packages, boxes);
    Assert(6, res);
    packages = { 2,3,5,8,7,6 };
    boxes = { {4,8},{2,8} };
    res = slu.minWastedSpace(packages, boxes);
    Assert(9, res);

    //CConsole::Out(res);
    
    • 1

    }

    2023年3月旧代码

    class Solution {
    public:
    int minWastedSpace(vector& packages, vector& boxes) {
    std::sort(packages.begin(), packages.end());
    vector vSums(1);
    for (const auto& pack : packages)
    {
    vSums.emplace_back(pack + vSums.back());
    }
    std::priority_queue que;
    for (auto& v : boxes)
    {
    std::sort(v.begin(), v.end());
    long long llCur = 0;
    int iHasDo = 0;
    for (int j = 0; j < v.size(); j++)
    {
    auto iCurDoEnd = std::upper_bound(packages.begin() + iHasDo, packages.end(), v[j]) - packages.begin();
    long long llCurBox = (long long)v[j] * (iCurDoEnd - iHasDo) - (vSums[iCurDoEnd] - vSums[iHasDo]);
    llCur += llCurBox;
    iHasDo = iCurDoEnd;
    }
    if (packages.size() == iHasDo)
    {
    que.push(llCur);
    if (que.size() > 1)
    {
    que.pop();
    }
    }
    }
    return que.size() ? C1097Int<>(que.top()).ToInt() : -1 ;
    }
    };

    扩展阅读

    视频课程

    有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
    https://edu.csdn.net/course/detail/38771

    如何你想快

    速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
    https://edu.csdn.net/lecturer/6176

    相关下载

    想高屋建瓴的学习算法,请下载《闻缺陷则喜算法册》doc版
    https://download.csdn.net/download/he_zhidan/88348653

    | 鄙人想对大家说的话
    |
    |-|
    |闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。|
    | 墨家名称的来源:有所得以墨记之。 |
    |如果程序是一条龙,那算法就是他的是睛|

    测试环境

    操作系统:win7 开发环境: VS2019 C++17
    或者 操作系统:win10 开发环境:

    VS2022 C++17

  • 相关阅读:
    docker 安装cloudreve
    【TypeScript基础】TypeScript之常用类型(上)
    Flink K8s Operator 测试验证
    gitignore: git上传时忽略不需要上传的文件
    Android Fragment动画实现
    目标检测系列算法:YOLOv7代码复现
    振弦采集仪安全监测路基边坡的解决方案
    优优嗨聚集团:OTC药品能否纳入报销成为各方关注焦点,对OTC医疗有何影响
    快速上手Linux核心命令(九):文件备份与压缩
    .net如何优雅的使用EFCore
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/134019227