Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务活动详情
一、题目描述
给定n个包裹,还有m个供应商,每个供应商都有一堆盒子,你可以选择某一个供应商,使用了他的盒子后你会造成一定的浪费(所有盒子与包裹之差的和),求选择哪一个供应商才能够达到最小的浪费程度。
数据范围
n <= 1e5
sigma(盒子) <= 1e5
二、思路分析
朴素想法: 首先肯定是需要排序的,包裹要排序,每个供应商的盒子也要排序。对于每一个供应商,我们用两个指针从头到尾扫下去,就能得到最优的方案,最后再比较每一个供应商即可。但是,这样子做复杂度就会爆炸了,每个供应商都要O(n)扫一遍,复杂度就是平方。
不朴素想法: 问题出在哪里?供应商肯定得一家家考虑,不能偷懒,那就是自己的箱子,一个个对比是不是符合当前的盒子,这种做法似乎有点浪费,显然可以用一个二分查找得出对于当前的盒子有多少个包裹是符合的,然后前缀和加加减减一下。复杂度怎么考虑呢?对于每一个盒子,它都对应了一次包裹的二分查找,所以是O(sigma(盒子)*log(n)),这是我们能接受的。
三、AC代码
class Solution {
public:
long long sum[100005];
long long js(vector<int>& packages, vector<int> boxes){
int n = packages.size();
int m = boxes.size();
long long wasted = 0;
sort(boxes.begin(), boxes.end());
if (packages[n-1] > boxes[m-1]) return -1;
int l=-1,r=0;
while (r<m){
if (boxes[r] < packages[l+1]) {
r++;
if (r==m) return -1;
continue;
}
int newl = upper_bound(packages.begin()+l+1, packages.end(), boxes[r]) -packages.begin()-1;
if (l<0) wasted += (long long)(newl-l)*boxes[r] - sum[newl];
else wasted += (long long)(newl-l)*boxes[r] - (sum[newl]-sum[l]);
l = newl;
if (l==n-1) break;
r++;
}
if (l!=n-1) return -1;
return wasted;
}
int minWastedSpace(vector<int>& packages, vector<vector<int>>& boxes) {
int n = packages.size();
int m = boxes.size();
long long ans=-1;
sort(packages.begin(), packages.end());
sum[0]=packages[0];
for (int i=1; i<n; i++) sum[i] = sum[i-1]+packages[i];
for (int j=0; j<m; j++) {
long long now = js(packages, boxes[j]);
if (now == -1) continue;
if (ans == -1) {
ans = now;
continue;
}
ans = min(ans, now);
}
return ans%(long long)(1e9+7);
}
};
四、总结
细节很多,写起来非常的难受。主要是自己对于 upper_bound 不熟悉,不太清楚一些细节与边界在哪里。
写的时候遇到了超时的问题,算来算去这个复杂度明明是没有问题的,折腾了半个小时,最终才查是问题出在哪里了。看下面这个地方,一开始我传vector的时候没有引用,而是直接深拷贝地复制一份.......在这个地方花费了大量的复杂度,还害我查了很久才查出来,真的很累人,是个坑,以后要长记性。
long long js(vector<int>& packages, vector<int> boxes)
long long now = js(packages, boxes[j]);
累吐了