题目描述

在一条环路上有 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 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油

开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油

开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油

开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油

开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油

开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。

因此,3 可为起始索引。

示例 2:

输入:

gas = [2,3,4]

cost = [3,4,3]

输出: -1

解释:

你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。

我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油

开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油

开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油

你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。

因此,无论怎样,你都不可能绕环路行驶一周。

解题思路

暴力解法

最简单的思路,就是判断当前索引i对应的gas[i]和cost[i]对应的大小情况。

如果gas[i] >= cost[i],则当前索引i的加油站可以被认为满足了1个条件,后续只要从它开始循环,如果能回到索引i,则这个索引是有效的;
否则,索引i+1,重新判断gas[i]和cost[i]对应的大小情况。
因为题目中已经给定了答案要么仅有一个,要么就没有。所以如果找到了那个索引i就可以从循环中跳出,下面给出“乞丐版”代码。其中的注释很详细。

“乞丐版”代码

class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int len = gas.size(); // 输入数组的长度
int tar = -1; // 这是需要返回的加油站索引,tar属于[0, len-1]
int rest; // 存放油箱的含油量
for (int i = 0; i < len; i++)
{
// 满足条件说明小车可以从当前加油站出发,接下来开始一个循环,判断小车是否能持续地回到加油站i
if (gas[i] >= cost[i])
{
int j; // 初始化待循环的变量
rest = gas[j] - cost[j]; // 初始化从加油站i出发时油箱中的油
for (j = (i+1) % len; j != i; j = (j+1) % len)
{
rest += gas[j]; // 小车能从加油站j获取油后油箱的含油量
rest -= cost[j]; // 小车到达加油站j+1消耗了油之后油箱的含油量 /* 如果邮箱含油量小于0,说明油箱中的油不足以支撑小车从加油站j到加油站j+1,
也就是说以加油站i作为起点不可行,在途中会遇到加油站j,此时油箱中的油不足以支撑小车从加油站j到加油站j+1 */
if (rest < 0)
break;
} // 如果j再次等于i,说明以加油站i作为起点可行,那么保存i到返回的变量tar中,然后跳出循环
if (i == j)
{
tar = i;
break;
}
}
}
// 如何tar还是-1,则说明遍历完所有加油站都没有找到合适的加油站,则返回-1
return (tar == -1 ? -1 : tar);
}
};
// “乞丐版”思路很简单,但是它最坏的复杂度能达到O(n^(2)),考虑用些trick将复杂度降低。

改进版

问:判断一个合格的加油站,除了从某个加油站i开始循环,最后回到加油站i这个方法之外,还有没有其他的办法?

答:有的,如果小车从所有加油站能获取的油 >= 跑完所有加油站所消耗的油,那么能断定可以找到某个加油站i,从i开始出发,最后能回到i。这个可以用反证法证明。但是如何找到那个加油站i?正因为题目中给出了一个条件,即这个加油站要么有且仅存在一个,要么没有,所以可以用算法很简单的实现。

下面给出算法,并在算法中给出详细注释

改进版算法

class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int len = gas.size(), rest = 0; // rest是小车油箱中剩余的油,初始化为0
int tar = 0; // tar存放的是可能合格的加油站索引,初始化为0
for (int i = 0; i < gas.size(); i++)
{
/* 算法主体:
如果小车油箱中剩余的油rest加上从加油站i获取的油能支撑它从加油站i跑到加油站i+1,那没问题,循环继续;
如果不足以支撑,那么当前的加油站i不可能是满足要求的加油站,将tar赋为下一个加油站i+1,并且将欠缺的油补到最后的一个加油站的cost。
之所以将欠缺的油补到最后的一个加油站是为了判断小车能获取的所有的油能否大于跑完所有加油站所消耗的油
*/
if (rest + gas[i] < cost[i])
{
tar = i + 1;
cost[len-1] += cost[i] - gas[i] - rest;
rest = 0;
}
else
{
rest += gas[i] - cost[i];
}
}
return (tar == len ? -1 : tar);
}
};

【leet-code】135. 加油站的更多相关文章

  1. [leet code 135]candy

    1 题目 There are N children standing in a line. Each child is assigned a rating value. You are giving ...

  2. 【Leet Code】Palindrome Number

    Palindrome Number Total Accepted: 19369 Total Submissions: 66673My Submissions Determine whether an ...

  3. Leet Code 771.宝石与石头

    Leet Code编程题 希望能从现在开始,有空就做一些题,自己的编程能力太差了. 771 宝石与石头 简单题 应该用集合来做 给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头. S  ...

  4. #Leet Code# Gray Code

    描述: 要求相邻数2进制差一位 先获得n-1的列表表示小于 2^(n-1) 的符合要求的列表,加上最高位的加成 2^(n-1) 就是大于等于 2^(n-1) 的符合要求的列表,后者翻转一下就能够与前者 ...

  5. #Leet Code# Permutation

    描述: 输出全排列 代码: class Solution: # @param num, a list of integer # @return a list of lists of integers ...

  6. #Leet Code# Unique Path(todo)

    描述: 使用了递归,有些计算是重复的,用了额外的空间,Version 1是m*n Bonus:一共走了m+n步,例如 m = 2, n = 3 [#, @, @, #, @],所以抽象成数学问题,解是 ...

  7. #Leet Code# Populating Next Right Pointers in Each Node II

    描述:注意需要先self.connect(right)再self.connect(left),否则会有case通不过,原因是左边递归执行时依赖与右边的next已经建立,而先执行connect(left ...

  8. #Leet Code# Sqrt

    描述:log(n) 代码: class Solution: # @param x, an integer # @return an integer def getVal(self, begin, en ...

  9. #Leet Code# Best Time to Buy and Sell Stock

    描述:数组 A,对于 i < j, 找到最大的 A[j] - A[i] 代码: class Solution: # @param prices, a list of integer # @ret ...

随机推荐

  1. 数据库的Connection、Cursor两大对象

    Python 数据库图解流程 Connection.Cursor比喻 Connection()的参数列表 host,连接的数据库服务器主机名,默认为本地主机(localhost). user,连接数据 ...

  2. [ 10.4 ]CF每日一题系列—— 486C

    Description: 给你一个指针,可以左右移动,指向的小写字母可以,改变,但都是有花费的a - b 和 a - z花费1,指针移动也要花费,一个单位花费1,问你把当前字符串变成回文串的最小化费是 ...

  3. pyqt5安装问题

    最近装了下pyqt5,遇到了很多坑,要么是模块没找到,要么是各种ddl出错什么的 后来查了一下,总结一下: 1.pyqt5和python的版本一定匹配,尤其是自己去网上下的pyqt一定要注意适配的版本 ...

  4. Git的分支管理

    0.引言 本文参考最后的几篇文章,将git的分支管理整理如下.学习git的分支管理将可以版本进行灵活有效的控制. 1.如何建立与合并分支 1.1分支的新建与合并指令 新建分支 newBranch,并进 ...

  5. SpringMVC拦截静态资源的处理办法

    SpringMVC拦截静态资源导致  JS  CSS  无法加载  可以在配置文件中加入以下代码 <mvc:resources location="/statices/" m ...

  6. 【转载】关于.NET下开源及商业图像处理(PSD)组件

    原创]关于.NET下开源及商业图像处理(PSD)组件   阅读目录 1 前言 2 .NET图像处理组件总结 3.相关资源网址        本博客所有文章分类的总目录:http://www.cnblo ...

  7. 背水一战 Windows 10 (111) - 通知(Tile): secondary tile 模板之图片, secondary tile 模板之分组

    [源码下载] 背水一战 Windows 10 (111) - 通知(Tile): secondary tile 模板之图片, secondary tile 模板之分组 作者:webabcd 介绍背水一 ...

  8. 背水一战 Windows 10 (101) - 应用间通信: 通过协议打开指定的 app 并传递数据以及获取返回数据, 将本 app 沙盒内的文件共享给其他 app 使用

    [源码下载] 背水一战 Windows 10 (101) - 应用间通信: 通过协议打开指定的 app 并传递数据以及获取返回数据, 将本 app 沙盒内的文件共享给其他 app 使用 作者:weba ...

  9. 剑指offer面试题17:合并两个排序的链表

    题目:输入两个递增排序的链表,合并这两个链表并使新链表中的节点人是按照递增排序的.解题思路:两个链表分别都已经是有序的了,遍历链表的时候只要比较两个链表当前位置大小,取出最小的添加到新链表中. 可以有 ...

  10. python异常报错详解

    异常BaseException所有内置异常的基类.它不是直接由用户定义的类继承(为此使用Exception).如果 str()或者unicode()是在这个类的一个实例上被调用,返回实例的参数表示形式 ...