【大根堆】【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++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++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat