最佳加油站选择算法:解决环路加油问题的两种高效方法|LeetCode力扣134

简介: 最佳加油站选择算法:解决环路加油问题的两种高效方法|LeetCode力扣134

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣!

期待与您一起探索技术、持续学习、一步步打怪升级 欢迎订阅本专栏❤️❤️

题目描述

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

注意:

  • 如果存在解,则保证该解为唯一的。

示例 1:

输入: 
gas  = [1,2,3,4,5]
cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站开始,可以获得 4 升汽油。出发后,油箱里有 4 升汽油。
开往 4 号加油站需要 1 升汽油,剩余 3 升汽油。
开往 5 号加油站需要 2 升汽油,剩余 1 升汽油。
开往 1 号加油站需要 3 升汽油,剩余 -2 升汽油。
开往 2 号加油站需要 4 升汽油,剩余 -1 升汽油。
开往 3 号加油站需要 5 升汽油,剩余 -6 升汽油。
由于油箱里有足够的汽油可以完成环路,所以返回 3。

示例 2:

输入: 
gas  = [2,3,4]
cost = [3,4,3]
输出: -1
解释:
你只能从 0 号或 1 号加油站出发,但都不能完成环路行驶一周。

方法一:贪心算法

解题步骤

  1. 初始化总油量 total_tank 和当前油量 curr_tank 为 0。
  2. 初始化起始站点 starting_station 为 0。
  3. 遍历每个加油站,计算 total_tankcurr_tank 分别增加当前站点的汽油量减去消耗量。
  4. 如果在某个站点 curr_tank 小于 0,说明无法从当前 starting_station 到达该站点,因此需要将 starting_station 更新为该站点的下一个站点,并将 curr_tank 置为 0。
  5. 遍历结束后,如果 total_tank 大于等于 0,返回 starting_station,否则返回 -1。

Python 示例

def canCompleteCircuit(gas, cost):
    total_tank, curr_tank = 0, 0
    starting_station = 0
    for i in range(len(gas)):
        total_tank += gas[i] - cost[i]
        curr_tank += gas[i] - cost[i]
        if curr_tank < 0:
            starting_station = i + 1
            curr_tank = 0
    return starting_station if total_tank >= 0 else -1
# Example usage
gas = [1, 2, 3, 4, 5]
cost = [3, 4, 5, 1, 2]
print(canCompleteCircuit(gas, cost))  # Output: 3
gas = [2, 3, 4]
cost = [3, 4, 3]
print(canCompleteCircuit(gas, cost))  # Output: -1

算法分析

  • 时间复杂度:O(N),其中 N 是加油站的数量。我们只需遍历一次所有的加油站。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

算法图解与说明

考虑 gas = [1, 2, 3, 4, 5], cost = [3, 4, 5, 1, 2]
总油量 total_tank = 0, 当前油量 curr_tank = 0, 起始站点 starting_station = 0
遍历每个加油站:
站点0: total_tank = -2, curr_tank = -2 (curr_tank < 0, 更新起始站点为1, curr_tank = 0)
站点1: total_tank = -4, curr_tank = -2 (curr_tank < 0, 更新起始站点为2, curr_tank = 0)
站点2: total_tank = -6, curr_tank = -2 (curr_tank < 0, 更新起始站点为3, curr_tank = 0)
站点3: total_tank = -3, curr_tank = 3 (curr_tank >= 0, 继续)
站点4: total_tank = 0, curr_tank = 4 (curr_tank >= 0, 继续)
总油量 total_tank >= 0,因此可以完成环路,返回起始站点3。

这种方法有效利用了贪心算法的思想,确保从正确的起始点开始能够完成环路行驶。

方法二:前缀和与一次遍历

解题步骤

  1. 初始化 total_tankcurr_tank 为 0,用于计算总油量和当前油量。
  2. 初始化起始站点 starting_station 为 0。
  3. 遍历每个加油站,计算从当前站点到下一个站点的油量差,并更新 total_tankcurr_tank
  4. 如果在某个站点 curr_tank 小于 0,说明无法从当前 starting_station 到达该站点。因此,将 starting_station 更新为该站点的下一个站点,并将 curr_tank 置为 0。
  5. 遍历结束后,如果 total_tank 大于等于 0,说明有解,返回 starting_station,否则返回 -1。

Python 示例

def canCompleteCircuit(gas, cost):
    total_tank, curr_tank = 0, 0
    starting_station = 0
    for i in range(len(gas)):
        total_tank += gas[i] - cost[i]
        curr_tank += gas[i] - cost[i]
        if curr_tank < 0:
            starting_station = i + 1
            curr_tank = 0
    return starting_station if total_tank >= 0 else -1
# Example usage
gas = [1, 2, 3, 4, 5]
cost = [3, 4, 5, 1, 2]
print(canCompleteCircuit(gas, cost))  # Output: 3
gas = [2, 3, 4]
cost = [3, 4, 3]
print(canCompleteCircuit(gas, cost))  # Output: -1

算法分析

  • 时间复杂度:O(N),其中 N 是加油站的数量。只需遍历一次所有的加油站。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。

算法图解与说明

考虑 gas = [1, 2, 3, 4, 5], cost = [3, 4, 5, 1, 2]
总油量 total_tank = 0, 当前油量 curr_tank = 0, 起始站点 starting_station = 0
遍历每个加油站:
站点0: total_tank = -2, curr_tank = -2 (curr_tank < 0, 更新起始站点为1, curr_tank = 0)
站点1: total_tank = -4, curr_tank = -2 (curr_tank < 0, 更新起始站点为2, curr_tank = 0)
站点2: total_tank = -6, curr_tank = -2 (curr_tank < 0, 更新起始站点为3, curr_tank = 0)
站点3: total_tank = -3, curr_tank = 3 (curr_tank >= 0, 继续)
站点4: total_tank = 0, curr_tank = 4 (curr_tank >= 0, 继续)
总油量 total_tank >= 0,因此可以完成环路,返回起始站点3。

这种方法与方法一的核心思想类似,但通过使用前缀和的概念更加简洁地实现了解决方案。核心在于每次从当前油量不足的地方重新开始计算起点,并最终判断总油量是否满足条件。

🌹🌹如果觉得这篇文对你有帮助的话,记得一键三连关注、赞👍🏻、收藏是对作者最大的鼓励,非常感谢 ❥(^_-)

❤️❤️作者知识有限,如有错误,请各位大佬评论区批评指正,不胜感激❥(^_-)

欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
30天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
10天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
23 2
|
1月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
38 2
|
1月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
1月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
51 9
|
1月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
49 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
1月前
|
算法
【链表】算法题(二) ----- 力扣/牛客
【链表】算法题(二) ----- 力扣/牛客
|
3月前
|
JavaScript 算法 前端开发
JS算法必备之String常用操作方法
这篇文章详细介绍了JavaScript中字符串的基本操作,包括创建字符串、访问特定字符、字符串的拼接、位置查找、大小写转换、模式匹配、以及字符串的迭代和格式化等方法。
JS算法必备之String常用操作方法