本文本质上为本人对力扣题解区灵茶山艾符的题解的理解.
这题主要难在读题. 要求的是最晚到达车站的时间, 且这个时间不能与其他人重合. 在评论区发现一个特别形象的解释, 这里引用一下:
看懂了题目就好做了, 我们乘车时间由两个因素限制: 要不晚于末班车的到达时间, 且要先于最后一个人到达车站(即进行插队操作). 由此得到了两种情况的答案求解过程: 1. 在公交车能载上所有人且还有剩余位置时, 我们只需在末班车到达时到达车站即可. 2. 在公交车不能运完所有人时, 我们就要比最后一个人先到, 但不能和其他人的到达时间重合, 我们在最后一个人的到达时间上进行递减操作, 找到最近的空闲时间即可(空闲指在此时间无人到达).
ranges::sort(buses);
ranges::sort(passengers);
int j = 0;
int c;
for (int t : buses) {
for (c = capacity; c && j < passengers.size() && passengers[j] <= t; c--) {
j++;
}
}
这段代码完成的是模拟操作, 我们按从早到晚的顺序遍历所有车辆, 并将能载走的乘客载走.c为车辆承载量, c小于0就说明这辆车已经满员了, 退出内层循环. j为当前要载的乘客, 当j大于passengers.size()时, 说明所有的乘客已被载走. passengers[j] <= t, t 为车辆到达时间, 因为先进行了排序, j所指的一定是当前最早的乘客, 如果passengers[j] > t, 说明车辆已经开走了, 我们可以直接退出内循环.
j--;
int ans = c ? buses.back() : passengers[j];
while (j >= 0 && ans == passengers[j]) {
ans--;
j--;
}
进行完模拟后, 我们对结果进行判断, 如果c不为零的话, 说明有多余的上车位置, 我们可以直接乘坐末班车. 那我们因为j大于passengers.size()或者passengers[j] > t 而退出循环会不会对结果产生影响呢. 答案是不会, 因为这两种方式退出循环会导致汽车空载, 也就是说, 车上仍有我们的上车位置, 所以不必担忧. 下面的while循环则是寻找到最晚的插队位置, 我们只要保证比最后一个人早一点点, 且跟其他人不重合就好啦
下面附上题解代码:
class Solution {
public:
int latestTimeCatchTheBus(vector<int>& buses, vector<int>& passengers, int capacity) {
ranges::sort(buses);
ranges::sort(passengers);
int j = 0;
int c;
for (int t : buses) {
for (c = capacity; c && j < passengers.size() && passengers[j] <= t; c--) {
j++;
}
}
j--;
int ans = c ? buses.back() : passengers[j];
while (j >= 0 && ans == passengers[j]) {
ans--;
j--;
}
return ans;
}
};