环形加油站问题

【数组】公交站间距离 环形数组 这道题实际考察的就是对边界的处理,最终能形成一个环形数组。我这里使用了深度优先搜索,直接做数据遍历就能算出来距离了。由于乘客只有2种情况会获得最小值,所以直接计算2次就能拿到结果。... 阅读详情

问题


城市的环形路有n个加油站,第i个加油站的油量用gas[i]来表示,你有如下的一辆车:

它的油缸是无限量的,初始是空的

它从第i个加油站到第i+1个加油站消耗油量为cost[i]

现在你可以从任意加油站开始,路过加油站可以不断的加油,问是否能够走完环形路。如果可以返回开始加油站的编号,如果不可以返回-1。

此题目来自于leetcode:https://oj.leetcode.com/problems/gas-station/

注意,解决方案保证是唯一的。

证明 
一个环形轨道上有n个加油站,所有加油站的油量总和正好够车跑一圈。证明,总能找到其中一个加油站,使得初始时油箱为空的汽车从这里出发,能够顺利环行一圈回到起点。

数学归纳法 
1)当n=1时,结论显然成立(汽车从唯一的加油站加油并出发); 
2)假设当n=k时结论成立,即公路上有k个加油站,从其中第m个加油站出发,汽车可以绕长为S1的公路一周;(为方便讨论,我们可以将原来的环状公路从出发站“剪开”,“拉直”为直线公路)

那么当n=k+1时,即增加一个站(第k+1个站),它携带着新的汽油,公路也因此延长了S=S2-S1的长度,新的汽油刚好可供汽车行驶距离S(这样便满足题设条件).我们不妨将第k+1个站放在原来第m个站的前面且与它的距离是S,则汽车从第k+1个站加油并出发,向第m个站开去,则刚好能到达第m个站,由(1)可知汽车可以走完长度为S1的公路,还原问题即得:汽车可以绕长为S2的公路一周.即当n=k+1时结论也成立.

由(1)和(2),可知结论对任意正整数n都成立,命题得证!

分析


这个题目其实比较简单,只要充分的理解,我相信大家都能够解决的。

你的这辆车的油缸是无限量的,所以每个加油站的油都可以加到车里,但是关键是你得保证,你在第i站的时候,油缸中有的油量,可以支撑你到第i+1站,对于每一站都要如此,所以,并不是总的油量大于消耗量就可以了。要保证每一站都有足够的油可以走到下一站,到每一站,你的车的油量都大于等于0就可以了。

经过上面的分析,很显然,暴力一点,我们每个站都试一下呗,然后找到每一站的油量都大于等于0的那个走法,返回开始的加油站;没有就返回-1。这个解法是O(n^2)的时间复杂度。

我们通过观察上面的暴力方法的步骤,可以发现有很大的改进空间。

当我们从第0个加油站开始,判断是否可以走完,然后从第1个加油站开始,进行判断的时候,其实中间的计算已经做过了。反过来,我们如果计算好了从第1个加油开始,到某一个站时,油量为tank,此时考虑从第0个开始时,到该加油站的油量就是gas[i]-cost[i] + tank。

这时隐约觉得,解决方案的时间复杂度可以是O(n)的时间复杂度。

事实上确实可以,具体的方法如下: 
tank表示当前车的油缸里的油量

从第0个站开始,tank += gas[0] - cost[0],只要tank>=0,我们就继续到下一个加油站

当不满足tank>=0,顺着环路试验从前一个站开始,比如,n-1: tank += gas[n-1] - cost[n-1],如果还小于0,继续试验再前一个。

直到满足 tank>=0,再进行第1步,依次类推

当一前一后这两个相遇了,算法也就结束了,tank>=0,就成功,返回相遇的位置;否则,失败,返回-1

上面这个方法的时间复杂度是多少呢?O(n)的,很简单,我们作为一个整体来看,每一个节点都只走了一次。

代码



class Solution
{
public:
int canCompleteCircuit(const vector<int> &gas, const vector<int> &cost)
{
    vector<int> line(gas.size( ) << 1);

    int n = line.size( );

    for(int i = 0; i < n; i++)
    {
        line[i] = gas[i % gas.size( )]- cost[i % gas.size( )];
    }

    int start = 0;
    int oil = 0;
    for(int i = 0; i < n; i++)
    {
        if (oil < 0)
        {
            start = i;
            oil = line[i];
        }
        else
        {
            oil += line[i];
            if (i - start >= gas.size( ))
            {
                return start;
            }
        }
    }
    return -1;
};

代码2


证明

总存在一个加油站,仅用它的油就足够跑到下一个加油站(否则所有加油站的油量加起来将 不够全程)。把下一个加油站的所有油都提前搬到这个加油站来,并把油已被搬走的加油站无视掉。在剩下的加油站中继续寻找油量足以到达下个加油站的地方,不断合并加油站,直到只剩一个加油站为止。显然从这里出发就能顺利跑完全程。

class Solution
{
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost)
    {

       int start = gas.size()-1;
       int end = 0;
       int sum = gas[start] - cost[start];
       while (start > end)
       {
          if (sum >= 0)
          {
             sum += gas[end] - cost[end];
             ++end;
          }
          else
          {
             --start;
             sum += gas[start] - cost[start];
          }
       }
       return sum >= 0 ? start : -1;

    }
};

网上神作


证明 
先让汽车油箱里装好足够多的油,随便从哪个加油站出发试跑一圈。车每到一个加油站时,记录此时油箱里剩下的油量,然后把那个加油站的油全部装上。试跑完一圈后,检查刚才路上到哪个加油站时剩的油量最少,那么空着油箱从那里出发显然一定能跑完全程。

算法思路为: 
1. 任取一个加油站,作为起点start,然后往前一直开,直到油不够。未能到达之站,记为end。

  1. 此时,说明start不适合作起点站。则偿试以start的前面一站作为起点,并更新start,再次偿试,看能否开到站点end。

  2. 如果不能开到站点end,说明此站也不合适,继续步骤2.

  3. 如果能开到站点end,则继续往前开。直到油不够,并更新end指向此未到之站。继续步骤2.

  4. 重复下去,直到start和end相遇。

在实现在,我将最后一个站点作为start,可以省去一个取模超作,即end前进可以简单的写作++end,而start后退可以简单的写作—start。

省去了写成 end = (end + 1)%N; start =(start + N -1)%N;

class Solution
{
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) 
    {
        int N = gas.size(), startIndex = -1;
        int sum = 0, total = 0;
        for(int i = 0; i < N; i++)
        {
            sum += (gas[i] - cost[i]);
            total += (gas[i] - cost[i]);

            if(sum < 0)
            {
                startIndex = i; 
                sum = 0;
            }
        }
        return total >= 0 ? startIndex + 1 : -1;
    }
}

此处贴上在网上看到的更好的优雅方案,供大家比较。

[cpp]  view plain  copy
  1. public class Solution {  
  2.     public int canCompleteCircuit(int[] gas, int[] cost) {  
  3.         // Note: The Solution object is instantiated only once and is reused by each test case.  
  4.         int N = gas.length, startIndex = -1;  
  5.         int sum = 0, total = 0;  
  6.         for(int i = 0; i < N; i++){  
  7.             sum += (gas[i] - cost[i]);  
  8.             total += (gas[i] - cost[i]);  
  9.             if(sum < 0){  
  10.                 startIndex = i;   
  11.                 sum = 0;  
  12.             }  
  13.         }  
  14.         return total >= 0 ? startIndex + 1 : -1;  
  15.     }  
  16. }  

注,此方案为Java语言实现,故接口与上C++实现略有不同。

其他示例: 
http://blog.chinaunix.net/uid-26456800-id-3456036.html

leetcode每日一道(15)环形路上加油站起点问题,绝妙思路 题目描述 环形路上有n个加油站,第i个加油站的汽油量是gas[i]. 你有一辆车,车的油箱可以无限装汽油。从加油站i走到下一个加油站(i+1)花费的油量是cost[i],你从一个加油站出发,刚开始的时候油箱里面没有汽油。 求从哪个加油站出发可以在环形路上走一圈。返回加油站的下标,如果没有答案的话返回-1。 注意: 答案保证唯一。 思路 其实比较容易想到,如果我随便选个起点,然后选择它的下一个加... 阅读详情

相关推荐

贪心算法在环形加油站问题中的实战与优化

本文深入解析了贪心算法在环形加油站问题中的应用与优化策略。通过分析汽车加油问题的核心性质,提出时间复杂度O(n)的贪心解法,并探讨了多种优化技巧和边界处理方案。文章还扩展了算法在实际物流调度等场景中的变体应用,帮助开发者掌握贪心算法的精妙使用场景。

weixin_31292729的博客 300

图解LeetCode——1184. 公交站间的距离(难度:简单)

思路一的好处是,对于正向或者逆向有一方步数较少时,我们可以不必等待步数较长一方执行完毕,只要以完成的一端可以确认路程最短,就可以结束遍历了。假设总的数组是[1,2,3,4,5,6,7,8],如果我们start=2,destination=7,那么。那么我们分别通过两个指针,从起点开始和从终点开始,进行行驶,虽然从终点到起点的计算路线也是正向的,但是根据题意实际上都是从起点到终点,【输入】distance=[1,2,3,4],start=0,destination=3。...

爪哇缪斯的博客 660

Gas Station (环形加油站)

题目:有n个加油站首尾相连成一个圆,已知每个加油站的油量,以及从第i个加油站到第i+1个加油站需消耗的油量,问:能否开车从某个加油站出发,循环一圈又回到起点,如果可以返回出发的起点(车的邮箱容量是无限的)。

elton_xiao的专栏 2030

leetcode 算法题1184 (简单306) 公交站间的距离

leetcode 算法题1184 (简单306) 公交站间的距离 题目介绍 环形公交路线上有 n 个站, 按次序从 0 到 n - 1 进行编号。 我们已知每一对相邻公交站之间的距离, distance[i] 表示编号为 i 的车站和编号为 (i + 1) % n 的车站之间的距离。 ...

FYuu95100的博客 736

Java 求解加油站

文章目录一、题目二、题解三、代码四、总结 一、题目 在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。 说明: 如果题目有解,该答案即为唯一答案。 输入数组均为非空数组,且长度相同。 输入数组中的元素均为非负数。 二、题解 暴力解法: 遍历每一个加油站,模拟一

南淮北安的博客 504

华为OD机试- 加油站(java& c++& python & javascript & golang & c# & c)

华为OD机试- 加油站(java& c++& python & javascript & golang & c# & c)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 450

算法工程师面试必备

今天跟大家分享一道算法题,不像之前的算法题,思路层层递进,这次可谓是三种截然不同的解法,相信大家能有所收获。01故事起源在一条圆形环路上有N个加油站,我们有一辆汽车,它的油箱容量无限,我们...

华章IT官方博客 611

避坑指南:STM32H7不同DMA控制器(MDMA/DMA2D/BDMA)到底该用哪个?

本文深入解析STM32H7系列芯片的DMA控制器选型策略,涵盖MDMA、DMA2D、BDMA等不同控制器的架构原理与性能对比。通过实际项目案例,提供高速TCM数据搬运、GUI加速、低功耗传输等场景的选型决策树,并分享性能优化与调试技巧,帮助工程师避开常见陷阱,提升系统效率。

weixin_26876073的博客 447

4.贪心-环形跑道 加油站问题(leetcode 134)

加油站,在一条环形路线上有 N 个加油站,其中第 i 个加油站的油量为 gas[i]。你有一辆油箱容量无限的汽车,从第 i 个加油站到下一个加油站(i+1)需要花费汽油费用[i]。您在其中一个加油站以空油箱开始旅程。如果可以绕行一圈,则返回起始加油站的索引,否则返回-1。将每个站的汽油含量-消耗量存放在tem数组中,同时使用currtotal作为总体标量来查看时候汽油数 >路程消耗数。同时curr作为当前油箱内 油量,如果curr

qq_73625278的博客 696

E5071C 网络分析仪使用指南

E5071C 网络分析仪是 Keysight(原 Agilent)推出的一款高性能矢量网络分析仪,广泛应用于射频(RF)和微波(MW)电路设计、天线测试、滤波器优化等领域。它以高精度、宽频率范围(9 kHz–20 GHz)、出色的动态范围和灵活的测量功能著称。本文将详细介绍 E5071C 的基本操作方法,帮助用户快速上手并高效使用该设备。

2501_90901792的博客 4186

UE 顶点动画工具 (VAT)

导入模型需要勾选全精度UV。

iesoxj的博客 1641

(贪心算法)环形加油站问题

/** * * @param gas int整型一维数组 * @param cost int整型一维数组 * @return int整型 */ function canCompleteCircuit( gas , cost ) { // write code here var start = gas.length - 1; var end ...

SevenLee的个人博客 590

基于单片机控制双向可控硅灯光强度设计

*单片机设计介绍,基于单片机控制双向可控硅灯光强度设计。

QQ2193276455的博客 2457

加油站问题:环形数组中的良好出发点

本文介绍了环形加油站问题的优化解法。题目要求在给定加油站油量和距离数组的情况下,找出所有能够完成一圈行驶的出发点(良好出发点)。相比暴力解的O(N²)复杂度,文章提出了使用前缀和与单调队列的O(N)优化方案: 构建扩展净油量数组(长度2N)并计算前缀和 使用单调队列维护滑动窗口最小值 对每个起始点i,检查窗口[i,i+N-1]内最小值是否≥prefix[i-1] 该算法通过环形数组扩展、前缀和转换和单调队列优化,将时间复杂度从O(N²)降为O(N)。

纳兰青华的博客 306

看懂 SAP S/4HANA 产品主数据里的 GTIN:一串号码背后的全球商品识别与业务协同

SAP S/4HANA中的GTIN管理是企业供应链运营的关键环节。本文深入解析GTIN的业务内涵及其在SAP系统中的实现方式:1) GTIN是全球通用的商品标识码,不同于企业内部物料编码;2) SAP主数据中GTIN与计量单位强绑定,需为不同包装层级维护独立GTIN;3) 同一产品可能因渠道、供应商差异存在多个GTIN;4) GTIN贯穿零售POS、仓储管理、EDI订单等核心业务流程;5) 通过典型案例说明错误维护GTIN将导致收银异常、仓库作业低效等运营问题。文章强调GTIN管理需结合包装层级、计量单位等

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1432

【AI大模型应用开发】【LlamaIndex教程】2. 存储模块:如何在 LlamaIndex 中使用自定义的向量数据库?(附代码)

前面文章两行代码就实现了文档的切分和向量化存储以及持久化存储。如果我们想用自定义的向量化数据库呢?

同学小张的博客 2117

加油站(贪心)【LeetCode】

加油站(贪心)【LeetCode】

『愚』的博客 1369

【华为OD机试真题】29、组成最大数 | 机试真题+思路参考+代码解析 (C++、Java、Py、C语言、JS)

题目描述 >小组中每位都有一张卡片,卡片上是6位内的正整数,将卡片连起来可以组成多种数字,计算组成的最大数字

KJ.JK 2418

N个加油站问题

问题:城市的环形路有n个加油站,第i个加油站的油量用gas[i]来表示,你有如下的一辆车: 它的油缸是无限量的,初始是空的 它从第i个加油站到第i+1个加油站消耗油量为cost[i] 现在你可以从任意加油站开始,路过加油站可以不断的加油,问是否能够走完环形路。如果可以返回开始加油站的编号,如果不可以返回-1。 https://leetcode.com/problems/ga

iihtd的专栏 1416

使用PostgreSQL构建高可用数据库集群

在现代企业级应用中,数据库的高可用性已成为业务连续性的核心要求。PostgreSQL作为一款功能强大的开源关系型数据库,其高可用架构的设计直接影响着系统的稳定性和可靠性。

九天的专栏 1258

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Leetcode134:加油站

文章目录题目描述思路分析 题目描述 示例 1: 输入: gas = [1,2,3,4,5] cost = [3,4,5,1,2] 输出: 3 解释: 从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油 开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油 开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油 开往 1...

sparky的博客 169

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

《leetcode-go》环形路加油站

环形路上有n个加油站,第i个加油站的汽油量是gas[i]. 你有一辆车,车的油箱可以无限装汽油。从加油站i走到下一个加油站(i+1)花费的油量是cost[i],你从一个加油站出发,刚开始的时候油箱里面没有汽油。 求从哪个加油站出发可以在环形路上走一圈。返回加油站的下标,如果没有答案的话返回-1。 注意: 答案保证唯一。 package main /** * * @param gas int整型一维数组 * @param cost int整型一维数组 * @return i

less_cold的博客 416

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

加油站-汽车问题

给定两个数列 P 和 D。P[i] 代表第 i 个加油站的油量,D[i] 代表从当前加油站到下一个加油站的距离。汽车每走单位距离,就会消耗单位油量。注意:加油站是环形单链表状的分布,也就是说,从当前加油站只能沿着一条仅有的路去向下一个加油站。 求一个起始加油站,从这个加油站出发,可以遍历所有加油站。 思路:通过 arr[i] = D[i] - P[i] 得到一个新的数组。用Kadane算法找出

jiyanfeng1的专栏 1139

找到起始加油站,使得汽车能够环绕一周的问题

Suppose there is a circle. You have five points on that circle. Each point corresponds to a petrol pump. You are given two sets of data.1. The amount of petrol that petrol pump will give.2. Dista...

ahen13519的博客 223
上一篇: 【推荐】二叉树的递归与非递归遍历实现
下一篇: Java中的ArrayList的初始容量和容量分配
大树叶
博客等级 码龄12年 1171粉丝 664原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值