【大根堆】【C++算法】871 最低加油次数

2024-01-26 22:12

本文主要是介绍【大根堆】【C++算法】871 最低加油次数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者推荐

【动态规划】【map】【C++算法】1289. 下降路径最小和 II

本文涉及知识点

大根堆 优先队列

LeetCode:871最低加油次数

汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。
沿途有加油站,用数组 stations 表示。其中 stations[i] = [positioni, fueli] 表示第 i 个加油站位于出发位置东面 positioni 英里处,并且有 fueli 升汽油。
假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 1 英里就会用掉 1 升汽油。当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。
为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 -1 。
注意:如果汽车到达加油站时剩余燃料为 0,它仍然可以在那里加油。如果汽车到达目的地时剩余燃料为 0,仍然认为它已经到达目的地。
示例 1:
输入:target = 1, startFuel = 1, stations = []
输出:0
解释:可以在不加油的情况下到达目的地。
示例 2:
输入:target = 100, startFuel = 1, stations = [[10,100]]
输出:-1
解释:无法抵达目的地,甚至无法到达第一个加油站。
示例 3:
输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]
输出:2
解释:
出发时有 10 升燃料。
开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。
然后,从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料),
并将汽油从 10 升加到 50 升。然后开车抵达目的地。
沿途在两个加油站停靠,所以返回 2 。
参数:
1 <= target, startFuel <= 109
0 <= stations.length <= 500
1 <= positioni < positioni+1 < target
1 <= fueli < 109

分析

加油站的位置已经按升序排序。
iCan 记录加油i次后,能到达的最远位置。i 取值区间[0,stations.length]
第i+1次加油,一定是iPreCan(第i次加油的iCan)能到达且没有加油,油量最大的加油站。
如果没有到达终点,且无油可加返回-1。

代码

核心代码

class Solution {
public:int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {int iCan = startFuel;priority_queue<int> canAdd;int j = 0;for (int i = 0; i < stations.size(); i++){if (iCan >= target){return i;}//canAdd能加油的加油站while ((j < stations.size()) && (stations[j][0] <= iCan)){canAdd.emplace(stations[j++][1]);}if (canAdd.empty()){return -1;}iCan += canAdd.top();canAdd.pop();}return (iCan >= target) ? stations.size() : -1;}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{	int target,  startFuel;vector<vector<int>> stations;{Solution sln;target = 1, startFuel = 1, stations = {};auto res = sln.minRefuelStops(target, startFuel, stations);Assert(res, 0);}{Solution sln;target = 100, startFuel = 1, stations = { {10,100} } ;auto res = sln.minRefuelStops(target, startFuel, stations);Assert(res, -1);}{Solution sln;target = 100, startFuel = 10, stations = { {10, 60},{20, 30},{30, 30},{60, 40} };auto res = sln.minRefuelStops(target, startFuel, stations);Assert(res, 2);}	{Solution sln;target = 100, startFuel = 50, stations = { {25, 25},{50, 50} };auto res = sln.minRefuelStops(target, startFuel, stations);Assert(res, 1);}}

2023年1月第一版

class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector>& stations) {
std::unordered_map<int,int> preDp;
preDp[0] = startFuel;
int iPrePos = 0;
for (auto& v : stations)
{
std::unordered_map<int, int> dp;
for (auto& pre : preDp)
{
const int iHasFuel = pre.second - (v[0] - iPrePos);
if (iHasFuel < 0 )
{
continue;
}
Add(dp, pre.first, iHasFuel);
Add(dp, pre.first+1, iHasFuel + v[1]);
}
preDp.swap(dp);
iPrePos = v[0];
}
int iMinNum = INT_MAX;
for (auto& pre : preDp)
{
const int iHasFuel = pre.second - (target - iPrePos);
if (iHasFuel < 0)
{
continue;
}
iMinNum = min(iMinNum, pre.first);
}
return (INT_MAX == iMinNum) ? -1 : iMinNum;
}
void Add(std::unordered_map<int, int>& dp, int iNum, int iFuel)
{
iFuel = min(iFuel, 1000 * 1000 * 1000);
auto it = dp.find(iNum);
if (dp.end() == it)
{
dp[iNum] = iFuel;
}
else
{
it->second = max(it->second, iFuel);
}
}
};

2023年1月 第二版

class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector>& stations) {
m_iFuel = startFuel;
for (auto& v : stations)
{
Add(v[0]);
if (m_iFuel < v[0])
{
return -1;
}
m_qFuel.push(v[1]);
}
Add(target);
if (m_iFuel < target)
{
return -1;
}
return stations.size() - m_qFuel.size();
}
void Add(int iNeedFuel)
{
while (m_qFuel.size() && (m_iFuel < iNeedFuel))
{
m_iFuel += m_qFuel.top();
m_qFuel.pop();
}
}
std::priority_queue m_qFuel;
int m_iFuel;
};

2023年 8月版

class Solution {
public:
int minRefuelStops(int target, int startFuel, vector<vector>& stations) {
stations.emplace_back(vector{target, 0});
int iRet = 0;
std::multiset setCanAdd;
int iHas = startFuel;
for (const auto& v : stations)
{
while (setCanAdd.size() && (iHas < v[0]))
{//油不够,需要加油
iHas += *setCanAdd.rbegin();
setCanAdd.erase(std::prev(setCanAdd.end()));
iRet++;
}
if (iHas < v[0])
{
return -1;
}
setCanAdd.emplace(v[1]);
}
return iRet;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

这篇关于【大根堆】【C++算法】871 最低加油次数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/648207

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域