最佳加油站选择算法:解决环路加油问题的两种高效方法|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。

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

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

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

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

相关文章
|
8天前
|
机器学习/深度学习 算法 C语言
详细介绍递归算法在 C 语言中的应用,包括递归的基本概念、特点、实现方法以及实际应用案例
【6月更文挑战第15天】递归算法在C语言中是强大力量的体现,通过函数调用自身解决复杂问题。递归涉及基本概念如自调用、终止条件及栈空间管理。在C中实现递归需定义递归函数,分解问题并设定停止条件。阶乘和斐波那契数列是经典应用示例,展示了递归的优雅与效率。然而,递归可能导致栈溢出,需注意优化。学习递归深化了对“分而治之”策略的理解。**
22 7
|
6天前
|
算法 Java
[Java·算法·简单] LeetCode 283. 移动零
[Java·算法·简单] LeetCode 283. 移动零
15 2
|
6天前
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
13 2
|
9天前
|
算法 Python
LeetCode 常用方法
LeetCode 常用方法
|
9天前
|
存储 算法 调度
力扣中级算法(Python)
力扣中级算法(Python)
|
9天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
9天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
9天前
|
算法 Python
力扣初级算法(Python)(二)
力扣初级算法(Python)(二)
|
9天前
|
算法 Python
力扣初级算法(Python)(一)
力扣初级算法(Python)(一)
|
10天前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素