【每日一题】出租车的最大盈利

文章目录

  • Tag
  • 题目来源
  • 解题思路
    • 方法一:递归
    • 方法二:递归+记录数组=记忆化搜索
    • 方法三:动态规划(递推)
  • 写在最后

Tag

【递归】【记忆化搜索】【动态规划】【数组】【2023-12-08】


题目来源

2008. 出租车的最大盈利


解题思路

以下题解与思路参考 教你一步步思考动态规划:从记忆化搜索到递推(Python/Java/C++/Go/JS/Rust)。

寻找子问题

假设 n = 9。我们要解决的问题是从 1 开车到 9 最多可以赚多钱。

会有以下两种情况出现:

  • 情况一:如果没有乘客在 9 下车,或者我们不搭载在 9 下车的乘客,那么问题就变成:从 1 开车到 8 最多可以赚多少钱;
  • 情况二:如果有至少一位乘客在 9 下车,我们可以枚举载哪位乘客。假设所载乘客在 5 上车,那么从 5 到 9 不能载其它乘客(题目要求同时最多只能接一个订单),问题变成:从 1 到 5 最多可以赚多少钱。

以上两种情况都会将原问题变成 「和原问题相似的、规模更小的子问题」,这意味着可以使用递归来解决问题。

方法一:递归

思路

递归函数定义为 dfs(i),表示从 1 开车到 i 最多可以赚多少钱。

情况一中问题变为:从 1 开车到 i-1 最多可以赚钱多少,有转移关系式:

d f s ( i ) = d f s ( i − 1 ) dfs(i) = dfs(i - 1) dfs(i)=dfs(i1)

在情况二中,我们可以枚举搭载哪位乘客,取其中最赚钱的方案,有转移关系式:

d f s ( i ) = m a x ( d f s ( s t a r t ) + i − s t a r t + t i p ) dfs(i) = max(dfs(start) + i - start + tip) dfs(i)=max(dfs(start)+istart+tip)
其中,start 表示到 i 的乘客的上车点,tip 为从 start 到 i 这一段路的小费。

以上两种情况取最大值得到 dfs(i),即

d f s ( i ) = m a x ( d f s ( i − 1 ) , m a x ( d f s ( s t a r t ) + i − s t a r t + t i p ) ) dfs(i) = max(dfs(i - 1), max(dfs(start) + i - start + tip)) dfs(i)=max(dfs(i1),max(dfs(start)+istart+tip))

递归边界:dfs(1) = 0,因为没有在 1 下车的乘客。

递归入口:dfs(n),也是最后需要返回的答案。

算法

在实现中,将 rides 数组按照下车点进行分组,方便枚举所有在 i 下车点下车的乘客。在分组中,使用 pair 记录每一个分组中的 startend - start + tip

class Solution {
public:long long maxTaxiEarnings(int n, vector<vector<int>>& rides) {vector<vector<pair<int, int>>> g(n+1);for (auto ride : rides) {int start = ride[0], end = ride[1], tip = ride[2];g[end].push_back(make_pair(start, end - start + tip));}function<long long(int)> dfs = [&](int i) -> long long {if (i == 0) {return 0;}long long res = dfs(i - 1);for (auto [s, t] : g[i]) {res = max(res, dfs(s) + t);}return res;};return dfs(n);}
};

该方法超时。

方法二:递归+记录数组=记忆化搜索

思路

由于在递归中存在某些 dfs(i) 重复计算的问题,因此可以使用一个数组 memo 记录计算结果,在递归中使用数据记录计算出的值的方法被称为「记忆化搜索」。

算法

class Solution {
public:long long maxTaxiEarnings(int n, vector<vector<int>>& rides) {vector<vector<pair<int, int>>> g(n+1);for (auto ride : rides) {int start = ride[0], end = ride[1], tip = ride[2];g[end].push_back(make_pair(start, end - start + tip));}vector<long long> memo(n+1, -1);    // -1 表示没有计算过function<long long(int)> dfs = [&](int i) -> long long {if (i == 0) {return 0;}auto& res = memo[i];    // 这里是引用,因为后面需要将更新后的 res 更新到 memo 中if (res != -1) {return res;}res = dfs(i - 1);for (auto [s, t] : g[i]) {res = max(res, dfs(s) + t);}return res;};return dfs(n);}
};

复杂度分析

时间复杂度: O ( n + m ) O(n+m) O(n+m)

空间复杂度: O ( n + m ) O(n+m) O(n+m)

方法三:动态规划(递推)

思路

将递归对应翻译为动态规划。

状态方程 f[i] 表示从 1 开车到 i 最多可以赚多少钱。

状态转移关系:

f [ i ] = m a x ( f [ i − 1 ] , m a x ( f [ s t a r t ] + i − e n d + t i p ) ) f[i] = max(f[i-1], max(f[start] + i - end + tip)) f[i]=max(f[i1],max(f[start]+iend+tip))

base case:f[1] = 0。

最后返回:return f[n]。

算法

class Solution {
public:long long maxTaxiEarnings(int n, vector<vector<int>>& rides) {vector<vector<pair<int, int>>> g(n+1);for (auto ride : rides) {int start = ride[0], end = ride[1], tip = ride[2];g[end].push_back(make_pair(start, end - start + tip));}vector<long long> f(n+1);    for (int i = 2; i <= n; ++i) {f[i] = f[i-1];for (auto [s, t] : g[i]) {f[i] = max(f[i], f[s] + t);}}return f[n];}
};

复杂度分析

时间复杂度: O ( n + m ) O(n+m) O(n+m),其中 m m mrides 的长度,n 是地点数目。动态规划转移需要 O ( n ) O(n) O(n) 的时间,查询乘客信息需要 O ( m ) O(m) O(m) 的时间。

空间复杂度: O ( n + m ) O(n+m) O(n+m)


写在最后

如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。

最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/257739.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Lidar】Python实现点云CSF布料滤波算法提取地面点

这两天会持续更新一下Python处理点云数据的教程&#xff0c;大家可以点个关注。今天给大家分享一下点云的经典算法&#xff1a;CSF布料模拟算法。 1 CSF算法简介 CSF算法&#xff0c;全称为Cloth Simulation Filtering&#xff0c;是一种基于欧几里得空间中最小生成树思想的聚类…

美颜SDK算法是什么?美肤、滤镜与实时处理技术讲解

美颜SDK的出现&#xff0c;为开发者提供了一种方便、高效的方式&#xff0c;使其能够轻松地将先进的美颜算法集成到各种应用中。本文将深入探讨美颜SDK算法的本质&#xff0c;以及其在美肤、滤镜与实时处理等方面的技术讲解。 一、美颜SDK算法简介 美颜SDK算法是一套通过计算…

Linux 常用命令汇总

1 linux定时任务 查看定时任务&#xff1a;crontab -l 每晚一点半执行定时任务&#xff1a; 30 1 * * * sh /var/lib/pgsql/pg_db_backup.sh >> /var/lib/pgsql/pg_db_backup.log 2>&1 配置定时任务&#xff1a;crontab -e 2 linux 内核版本查询 cat /etc/r…

Java 中 char 和 Unicode、UTF-8、UTF-16、ASCII、GBK 的关系

Unicode、UTF-8、UTF-16、UTF-32、ASCII、GBK、GB2312、ISO-8859-1 它们之间是什么关系? 关于这几种字符编码的关系,经过各种资料研究,总结如下图(请右键在新标签页打开查看或者下载后使用看图工具放大查看): 我们应该从历史的顺序看待这些字符编码的由来: ASCII(早期…

二十一章(网络通信)

计算机网络实现了多台计算机间的互联&#xff0c;使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序&#xff0c;这些程序借助于网络协议&#xff0c;相互之间可以交换数据。编写网络应用程序前&#xff0c;首先必须明确所要使用的网络协议…

“身份证信息批量核验:高效解决管理难题,轻松提升工作效率“

尊敬的读者们&#xff0c;您是否曾经因为身份证信息的核验而感到烦恼&#xff1f;是否曾经因为手动核验而感到繁琐和耗时&#xff1f;现在&#xff0c;我们向您介绍一款全新的工具——身份证信息批量核验器&#xff0c;它将帮助您一键解决管理难题&#xff0c;让工作事半功倍&a…

【PyTorch】 暂退法(dropout)

文章目录 1. 理论介绍2. 实例解析2.1. 实例描述2.2. 代码实现2.2.1. 主要代码2.2.2. 完整代码2.2.3. 输出结果 1. 理论介绍 线性模型泛化的可靠性是有代价的&#xff0c;因为线性模型没有考虑到特征之间的交互作用&#xff0c;由此模型灵活性受限。泛化性和灵活性之间的基本权…

整理了一些WPF的布局

在Grid里对一个TextBox定位 <Grid ShowGridLines"True"><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><…

linux的定时任务Corntab

安装crontab # yum安装crontab yum install -y crontab# 开机自启crond服务并现在启动 systemctl enable --now crondcron系统任务调度 系统任务调度&#xff1a; 系统周期性所要执行的工作&#xff0c;比如写缓存数据到硬盘、日志清理等。 在/etc/crontab文件&#xff0c;这…

selenium 解决 id定位、class定位中,属性值带空格的解决办法

一、前置说明 selenium遇到下面这种元素&#xff1a; <th id"demo id" class"value1 value2 value3 ">1、虽然id一般不会有空格&#xff0c;但是前端错误的这种写法(如下图)&#xff0c;会造成使用id定位不到元素&#xff0c;如&#xff1a; find…

新生儿出生缺陷筛查的关键注意事项

引言&#xff1a; 新生儿的出生缺陷是一个复杂而广泛的问题&#xff0c;及早的筛查和诊断对于预防和管理这些缺陷至关重要。出生缺陷可能涉及各个系统&#xff0c;包括心脏、神经、遗传等&#xff0c;因此及时而全面的筛查对新生儿的健康至关重要。本文将深入探讨新生儿出生缺…

力扣题:字符的统计-12.6

力扣题-12.6 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;696. 计数二进制子串 解题思想&#xff1a;先统计连续的0和连续的1的个数&#xff0c;然后进行相加即可&#xff08;想不到一点&#xff09; class Solution(object):def countBinaryS…