LeetCode-2008. 出租车的最大盈利
题目描述
你驾驶出租车行驶在一条有 n
个地点的路上。这 n
个地点从近到远编号为 1
到 n
,你想要从 1
开到 n
,通过接乘客订单盈利。你只能沿着编号递增的方向前进,不能改变方向。
乘客信息用一个下标从 0 开始的二维数组 rides
表示,其中 rides[i] = [starti, endi, tipi]
表示第 i
位乘客需要从地点 starti
前往 endi
,愿意支付 tipi
元的小费。
每一位 你选择接单的乘客 i
,你可以 盈利 endi - starti + tipi
元。你同时 最多 只能接一个订单。
给你 n
和 rides
,请你返回在最优接单方案下,你能盈利 最多 多少元。
注意:你可以在一个地点放下一位乘客,并在同一个地点接上另一位乘客。
问题分析
从打家劫舍的角度分析
预处理:将所有区间按照右端点,从小到大排序。
状态定义:dp[i]
表示到第 i 个乘客时,能够获取的最大利润。
考虑第 i 个乘客时,可能有两种情况:
- 第
i
个乘客不接,即从第i-1
个乘客的最大利润转移过来 - 第
i
个乘客要接,即从第j
个乘客的最大利润转移过来。其中满足第j
个乘客的下车点小于等于第i
个乘客的上车点。
综上所述,可以得到如下的状态转移方程:dp[i] = max(dp[i-1], dp[j] + ed - st + tip)
从终点的角度分析
预处理:用哈希表存储每个在地点i
下车的乘客的信息。
状态定义:dp[i]
表示到第 i 个地点时,能获得的最大利润。
状态计算:
- 第
i
个地点没有乘客下车:dp[i] = dp[i-1]
- 第
i
个地点有乘客下车:遍历所有在第i
个地点下车的乘客,找最大利润dp[i] = max(dp[i], dp[st] + ed - st + tip)
程序代码
打家劫舍角度
class Solution {
public:
long long maxTaxiEarnings(int n, vector<vector<int>>& rides) {
int k = rides.size();
vector<long long> dp(k + 1);
sort(rides.begin(), rides.end(), [](const vector<int>& a, const vector<int>& b) { return a[1] < b[1]; });
for(int i = 1; i <= k; i++) {
int st = rides[i-1][0], ed = rides[i-1][1], tip = rides[i-1][2];
auto it = lower_bound(rides.begin(), rides.begin() + i, st + 1, [](auto& a, int val) { return a[1] < val; });
int j = distance(rides.begin(), it);
dp[i] = max(dp[i-1], dp[j] + ed - st + tip);
}
return dp[k];
}
};
终点角度
class Solution {
public:
long long maxTaxiEarnings(int n, vector<vector<int>>& rides) {
vector<long long> dp(n + 1);
unordered_map<int, vector<vector<int>>> rideMap;
for(const vector<int>& r : rides) {
rideMap[r[1]].push_back(r);
}
for(int i = 1; i <= n; i++) {
dp[i] = dp[i-1];
for(const vector<int>& r : rideMap[i]) {
dp[i] = max(dp[i], dp[r[0]] + r[1] - r[0] + r[2]);
}
}
return dp[n];
}
};