1. 题意
有n段旅程,每段旅程由上车点、下车点、上车人数组成。
求给定的旅程是否能让所有旅程顺利完成。
拼车
2. 题解
首先肯定要将旅程按上车位置进行排序。
2.1 模拟+小根堆
根据下车时间的早晚创建一个小根堆。
在每次进行新的旅程前判断是否有人下车了,即在堆非空情况下,判断最早下车旅程是否小于下一段旅程的起始点。
若有人下车,即将堆顶得到旅程给弹出释放车上的空位,直到堆中无元素或堆顶下车时间大于新旅程的上车时间。
若无人下车或堆空,则判断是否有足够的位置容纳新的旅程。
没有则返回结果,有则插入该旅程并减小容纳位置。
class Solution {
public:struct trip {trip( const vector<int> &arr){p = arr[0];f = arr[1];t = arr[2];}bool operator <(const trip &b) const{ return t > b.t;}int p;int f;int t;};bool carPooling(vector<vector<int>>& trips, int capacity) {sort(trips.begin(), trips.end(),[](const vector<int> &a, const vector<int> &b){ if ( a[1] == b[1])return a[2] < b[2];return a[1] < b[1];});priority_queue<trip> pq;int sz = trips.size();for (vector<int> &t: trips) { trip v(t);while ( !pq.empty() ) {auto top = pq.top();if (top.t > v.f)break;capacity += top.p;pq.pop();}if ( capacity < v.p )return false;capacity -= v.p;pq.push(v);}return true;}
};
2.2 判断每个位置是否合理+差分
由于我们并不在意实际在哪上下,而只是在意是否能容纳。
我们可以反向考虑每个位置点车上的总人数,如果大于了最大容量则不能完成;
否则可以完成该旅程。
所以可以用一个数组标识每个位置点上的总人数。
添加旅程的时候,将起始点到结束点范围的状态位置更新。
最后再判断是否有位置点超过最大容量即可。
- 简单区间更新
class Solution {
public:bool carPooling(vector<vector<int>>& trips, int capacity) {int num[1001]={0};for (auto &v: trips) {for (int i = v[1]; i < v[2]; ++i) {num[i] += v[0];}}for (int i = 0 ; i <= 1000; ++i) {if ( num[i] > capacity)return false;}return true;}
};
- 差分
由于这里是区间进行更新相同值,而且我们最终还是要遍历每个点的;所以可以直接使用差分进行更新。
class Solution {
public:bool carPooling(vector<vector<int>>& trips, int capacity) {int num[1001]={0};for (auto &v: trips) {num[v[1]] += v[0];num[v[2]] -= v[0]; }int prefix = 0;for (int i = 0 ; i <= 1000; ++i) {prefix += num[i];if ( prefix > capacity)return false;}return true;}
};