一、环境说明
- 本文是 LeetCode 2008题 : 出租车的最大盈利,使用c语言实现。
- 动态规划。
- 测试环境:Visual Studio 2019。
二、代码展示
#define Max(a,b) ((a)>(b)?(a):(b))
int cmp(const void *a,const void *b){
return (*((int**)a))[1] - (*((int**)b))[1];//按照end升序
}
long long maxTaxiEarnings(int n, int** rides, int ridesSize, int* ridesColSize){
qsort(rides,ridesSize,sizeof(rides[0]),cmp);//按照end升序
int i = 1,j=0;//遍历的两个位置
long long dp[n+1];//最大dp[n]
memset(dp,0,sizeof(long long)*n);//初始化dp为0
while(i<=n){//一直遍历到dp[n]
dp[i]=dp[i-1];
while(j<ridesSize&&i==rides[j][1]){//j用于遍历rides。当终点i==rides[j][1]时,说明需要更新dp了。
int end =rides[j][1];//终点
int start = rides[j][0];//起点
int tips = rides[j][2];//小费
dp[i]=Max(dp[i],dp[start]+end - start +tips);
j++;//找下一个j//这里可以二分查找优化//参考1235题官解。
}
i++;
}
return dp[n];
}
三、思路分析
- 动态规划。
- 分析怎么设计 d p dp dp 。区间动态规划的较好处理是:遍历 r i d e s rides rides ,找目前最早的结束地点 e n d end end 。
- 同时遍历 n n n 和 r i d e s rides rides ,用 i i i 表示 n n n 当前位置,用 j j j 表示 r i d e s rides rides 当前位置。
- 我们对 r i d e s rides rides 按 e n d end end 升序快排,当前位置 j j j 就是目前最早的 e n d end end 。
- 记 f [ i ] f[i] f[i] 为 i i i 位置前的最大盈利。对于位置 i i i ,最大盈利 f [ i ] f[i] f[i] 可能等于 f [ i − 1 ] f[i-1] f[i−1] ,也可能等于 f [ j ] + e n d − s t a r t + t i p s f[j]+end-start+tips f[j]+end−start+tips ,所以设计 f [ i ] = M a x ( f [ i − 1 ] , f [ j ] + e n d − s t a r t + t i p s ) f[i]=Max(f[i-1],f[j]+end-start+tips) f[i]=Max(f[i−1],f[j]+end−start+tips) 。 j j j 是以 i i i 作为 e n d end end 的一个起始地点。
- 提示: i i i 之前上车的顾客,可能不止一个人在 i i i 下车。所以我们用 j j j 遍历 r i d e s rides rides ,确保每个顾客都被考虑。
状态转移方程 :
f [ i ] = { f [ i − 1 ] if 不 上 车 f [ s t a r t ] + e n d − s t a r t + t i p s if 上 车 f[i] = \begin{cases} f[i-1] &\text{if } 不上车 \\ f[start]+end-start+tips &\text{if } 上车 \end{cases} f[i]={f[i−1]f[start]+end−start+tipsif 不上车if 上车
四、代码分析
- 理解思路很重要!
- 欢迎读者在评论区留言,作为日更博主,看到就会回复的。
五、AC
第一次双百。
六、复杂度分析
复杂度小知识: 时空复杂度是大致级别。规则 : ①忽略常数; ②同变量忽略较低数量级,如 O ( m l o g 2 m + m ) O(mlog_2m +m) O(mlog2m+m) ,保留 O ( m l o g m ) O(mlogm) O(mlogm) 即可。
- 时间复杂度: O ( n + m l o g m ) O(n+mlogm) O(n+mlogm) , n n n 是地点总数, m m m 是 r i d e s rides rides 的大小。
提示: 快排 r i d e s rides rides 的平均时间复杂度是 O ( m l o g 2 m ) O(mlog_2m) O(mlog2m) ,这是在快排的分治操作下,算法本身决定的。
代码中,出现 w h i l e while while 嵌套 w h i l e while while ,看似时间复杂度要乘起来,其实是相加,因为我们限制 i 、 j i、j i、j 在循环中只会后移,不会回退 。遍历 n n n 个地点的时间复杂度是 O ( n ) O(n) O(n) , 遍历 r i d e s rides rides 的时间复杂度是 O ( m ) O(m) O(m),二者是相加关系 。
总体时间复杂度是 O ( m l o g 2 m + n + m ) O(mlog_2m + n+m) O(mlog2m+n+m) , O ( m ) < O ( m l o g 2 m ) O(m)<O(mlog_2m) O(m)<O(mlog2m) ,忽略 O ( m ) O(m) O(m) ,最终时间复杂度 O ( m l o g m + n ) O(mlogm + n) O(mlogm+n)。
- 空间复杂度: O ( n + l o g m ) O(n + logm) O(n+logm) , d p [ n ] dp[n] dp[n] 的空间复杂度 O ( n ) O(n) O(n) ,快排 r i d e s rides rides 的空间复杂度是 O ( l o g m ) O(logm) O(logm) 。
提示: 快排的空间复杂度由算法本身决定。
d
p
[
N
]
dp[N]
dp[N] 是一开始定义好的。