👉 “Offer 驾到,掘友接招!我正在参与2022春招打卡活动点击查看 活动详情。
1889. 装包裹的最小浪费空间
给你 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 。
由于答案可能会 很大 ,请返回它对 取余 的结果。
示例 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 <= 10^5
1 <= m <= 10^5
1 <= packages[i] <= 10^5
1 <= boxes[j].length <= 10^5
1 <= boxes[j][k] <= 10^5
sum(boxes[j].length) <= 10^5
boxes[j] 中的元素 互不相同 。
解题思路:
对于每个供应商提供的箱子,每个包裹需要选择不小于包裹尺寸的最小的箱子。
用示例3的供应商3举例:
| packages | 3 | 5 | 8 | 10 | 11 | 12 |
|---|---|---|---|---|---|---|
| box | 5 | 5 | 10 | 10 | 14 | 14 |
这里考虑二分查找,对于每个供应商提供的一组箱子,从小到大遍历箱子的尺寸,然后尽可能放入更多的包裹。如果包裹已经被之前的箱子放入了,那么就不在考虑放到当前箱子里面。
C++的STL库中有个upper_bound,就是找到大于当前值的第一个位置。如果这个值是箱子尺寸,那么找到的位置就是当前箱子放不下的第一个包裹的位置。
这里还需要用前缀和来处理一下包裹的容量和,方便计算
一些情况的处理:
如果供应商提供的箱子中的最大值小于最大包裹的尺寸,就是无法将包裹放进箱子里面。
代码如下:
class Solution {
public:
int minWastedSpace(vector<int>& packages, vector<vector<int>>& boxes) {
// 排序包裹
sort(packages.begin(), packages.end());
// 包裹容量和前缀
vector<long long> prefix{0};
for(auto it: packages){
prefix.push_back(prefix.back() + it);
}
int maxBox = 0;
long long ret = LONG_LONG_MAX;
// 遍历每一个供应商
for(auto& box: boxes){
// 排序箱子
sort(box.begin(), box.end());
if(box.back() < packages.back()){
continue;
}
long long tmp = 0;
long long prev = 0;
// 遍历供应商的每一个箱子
for(int i = 0; i < box.size(); ++i){
// 找到箱子放不下的包裹的第一个位置
auto pos = upper_bound(packages.begin(), packages.end(), box[i]) - packages.begin();
// 用当前箱子的总尺寸 减去 当前箱子放下的包裹的总尺寸
tmp += 1ll * (pos - prev) * box[i] - 1ll * (prefix[pos] - prefix[prev]);
prev = pos;
}
ret = min(ret, tmp);
}
if(ret == LONG_LONG_MAX){
return -1;
}else{
return ret % 1000000007;
}
}
};
- 时间复杂度
- 空间复杂度