你驾驶出租车行驶在一条有 n
个地点的路上。这 n
个地点从近到远编号为 1
到 n
,你想要从 1
开到 n
,通过接乘客订单盈利。你只能沿着编号递增的方向前进,不能改变方向。
乘客信息用一个下标从 0 开始的二维数组 rides
表示,其中 rides[i] = [starti, endi, tipi]
表示第 i
位乘客需要从地点 starti
前往 endi
,愿意支付 tipi
元的小费。
每一位 你选择接单的乘客 i
,你可以 盈利 endi - starti + tipi
元。你同时 最多 只能接一个订单。
给你 n
和 rides
,请你返回在最优接单方案下,你能盈利 最多 多少元。
**注意:**你可以在一个地点放下一位乘客,并在同一个地点接上另一位乘客
首先,注意题目所说,司机一次只能接一个订单
寻找子问题
以 从1开到9 为例,如果我们要计算从1-9要赚多少钱
如果 在 9 没有乘客 下车 或者 没有乘客在车上,
那么就变成了 计算 从1-8 要赚多少钱
如果在 9 有乘客下车,那么我们枚举 在9处下车的订单,哪个赚的最多,如果从5上车到9下车的订单赚的最多
那么就变成了 计算 从 1-5 要赚多少钱
每个地点,我们都考虑, 有或没有
如同上面的思考方式,在每个地点,我们都可以转换 为前面地点,即子问题的考虑,符合状态转移的思想
所以用动态规划来解决
动态规划五部曲
1.确定dp[ i ]的下标和意义:
dp[ i] 代表从0开到i 处的最大盈利
2.确定递推公式:
如果 i处无乘客 下车,
则 dp[ i] =dp[ i-1]
如果i处 有乘客下车 ,那么枚举i处下车的订单得到利润最大的订单j
则 dp[ i] =dp[ rides[j] [0] ] + rides[j] [1]-rides[j] [0] +rides[j] [2]
取两者的max
3.初始化dp
开始无收入,所以都初始化为0
4.确定遍历顺序:
dp[i ]是由 dp[ i-1] 和dp [rides[j] [0]] 推导出来的
所以遍历顺序应该从前到后
5.打印
代码
class Solution{
public long maxTaxiEarnings(int n, int[][] rides) {
//用map记录每个订单,以下车点为key,方便后面 对下车订单的枚举
Map<Integer, List<int[]>> record=new HashMap<>();
for(int ride[]:rides){
List<int[]>list=record.getOrDefault(ride[1],new ArrayList<>());
list.add(new int[]{ride[0],ride[2]});
record.put(ride[1] ,list);
}
long[] dp=new long[n+1];
for(int i=1;i<=n;i++){
//此地点无乘客下车的情况:no
long no=dp[i-1];
//此地点有乘客下车的情况:yes
long yes=0;
if(record.containsKey(i)){
List<int[]> personList= record.get(i);
for(int[] person:personList){
yes=Math.max(yes,i-person[0]+person[1]+dp[person[0]]);
}
}
dp[i]=Math.max(yes,no);
}
return dp[n];
}
}
参考:
灵神题解