题目描述
你驾驶出租车行驶在一条有 n
个地点的路上。这 n
个地点从近到远编号为 1
到 n
,你想要从 1
开到 n
,通过接乘客订单盈利。你只能沿着编号递增的方向前进,不能改变方向。
乘客信息用一个下标从 0
开始的二维数组 rides
表示,其中 rides[i] = [starti, endi, tipi]
表示第 i
位乘客需要从地点 starti
前往 endi
,愿意支付 tipi
元的小费。
每一位你选择接单的乘客 i
,你可以盈利 endi - starti + tipi
元。你同时最多只能接一个订单。
给你 n
和 rides
,请你返回在最优接单方案下,你能盈利最多多少元。
注意:你可以在一个地点放下一位乘客,并在同一个地点接上另一位乘客。
做题情况
- 做出来且思路与标答一致
- 做出来但思路较为复杂
- 有思路,但时间复杂度较高无法通过
- 没有思路 ☑
自己的想法:
自己其实是有一些思路的,但是不是很多,自己知道应该用动态规划来解,不过可能确实有点问题,自己没有绕过来,即使告诉自己怎么做,自己得到这个解的可行性还是需要一定时间。
总结了一下,可能存在这样的问题:
1.二分法真的是自己的短板。
2.这类题的动态规划自己掌握的不是很好。
标答:动态规划+二分法
这个题有几个需要注意的问题:
1.排序要按照结束时间的顺序来。这一点是从贪心得到的思路,结束时间早才是真的早,且开始时间一定是早于结束时间的,这相当于既限制了开始时间,又限制了结束时间。
2.动态规划。我们设置的是可以取开始到当前这些客人所取到的最大值。在进行循环更新时,我们会回到可以放的下当前客人的最晚位置。这个地方的可行性自己绕了很久才明白(之前自己也有一个题绕了很久也不明白,也许这两道题之间存在联系)。首先这个位置之后一定是不能和当前客人同时取到的,即使他们接送那个位置的客人,也是会回到最晚位置之前的。最晚位置一定可以取到当前客人,且比前面的值一定大。
如果不取当前的客人,那么就直接等于前面一个的最大值就可以了。
这个明天自己再想一下吧,感觉是自己之前所没有想过的问题。
3.二分法。这个自己是真的不熟,很多时候就是因为没有想到二分法导致自己没有想出来。n*logn的复杂度自己一定要想一下二分法,别只惦记着排序这类东西了。
实际代码
class Solution {
public:
struct Ride
{
int start;
int end;
int tip;
Ride(){}
Ride(int a,int b,int c)
{
start=a;
end=b;
tip=c;
}
bool operator < (const Ride& other) const
{
if (end!=other.end) return end<other.end;
else if (start!=other.start) return start<other.start;
else return tip>other.tip;
}
};
static bool cmp(int x,const Ride& ride)
{
return x<ride.end;
}
long long maxTaxiEarnings(int n, vector<vector<int>>& rides)
{
//第一想法是动态规划,其实可以按照结束时间来排序的
//想了一下应该是可行的,先结束时间排序,再把每一个都放入到优先队列里面
int m=rides.size();
vector<Ride> vec(m);
for (int i=0;i<rides.size();++i)
{
vec[i]=Ride(rides[i][0],rides[i][1],rides[i][2]);
}
sort(vec.begin(),vec.end());
vector<long long> dp(m+1,0);
for (int i=0;i<m;++i)
{
int j=upper_bound(vec.begin(),vec.begin()+i,vec[i].start,cmp)-vec.begin();
dp[i+1]=max(dp[i],dp[j]+vec[i].end-vec[i].start+vec[i].tip);
}
return dp[m];
}
};
总结
这个题还是很值得好好想一下的,这些有多个维度的题,自己总是有点问题,之后再多想一点!