LC826. 安排工作以达到最大收益
思路
- 将工作按照难度进行排序。难度越大不一定收益就越多,但是可以在预处理(左边最大值辅助数组)之后,在O(1)时间内得知,满足条件的区间里面最大的收益值是多少。
- 所谓预处理,就是建立一个
left_max
数组,该数组记录了出现在左边的最大值,left_max[i]
表示从第0
个位置,到第i
个位置,出现的最大的数值。 - 对于工人
i
而言,可以通过二分查找,在时间内找到difficulty
值不大于worker[i]
的区间的右端点,该端点记为x
,那么这个工人能取得的最大收益就是left_max[x]
。
left_max
数组预处理,left_max[i]
表示从0
到i
的最大数字 ```cpp vectorleft_max(n, 0); left_max[0] = pp[0].second;
for (int i = 1; i < n; i++) { left_max[i] = max(left_max[i - 1], pp[i].second); }
- 二分查找,找左侧区间的右端点
```cpp
while (left < right) {
int mid = (left + right + 1) / 2;
if (pp[mid].first <= num) {
left = mid;
} else {
right = mid - 1;
}
}
代码
class Solution {
public:
int findEnd(int num, vector<pair<int,int>>& pp) {
int n = pp.size();
int left = 0, right = n - 1;
while (left < right) {
int mid = (left + right + 1) / 2;
if (pp[mid].first <= num) {
left = mid;
} else {
right = mid - 1;
}
}
if (pp[right].first <= num) {
return right;
} else {
return -1;
}
}
static bool cmp(const pair<int, int> p1, const pair<int, int> p2) {
return p1.first < p2.first;
}
int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
int n = difficulty.size();
vector<pair<int, int>> pp(n, {0, 0});
for (int i = 0; i < n; i++) {
pp[i].first = difficulty[i];
pp[i].second = profit[i];
}
sort(pp.begin(), pp.end(), cmp);
// 对于每个满足条件的条件,计算左边开始的最大收益值
vector<int> left_max(n, 0);
left_max[0] = pp[0].second;
for (int i = 1; i < n; i++) {
left_max[i] = max(left_max[i - 1], pp[i].second);
}
int cnt = 0;
// 找到满足工人能力条件的区间的右端点,然后计算这个区间曾经出现过的最大值即可
int worker_num = worker.size();
for (int i = 0; i < worker_num; i++) {
int right_end = findEnd(worker[i], pp);
if (right_end == -1) {
continue;
} else {
cnt += left_max[right_end];
}
}
return cnt;
}
};