前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Leetcode No.134 加油站

Leetcode No.134 加油站

作者头像
week
发布2022-01-06 10:19:12
2510
发布2022-01-06 10:19:12
举报
文章被收录于专栏:用户画像

题目描述

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。

说明: 如果题目有解,该答案即为唯一答案。 输入数组均为非空数组,且长度相同。 输入数组中的元素均为非负数。

代码语言:javascript
复制
示例 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 可为起始索引。

代码语言:javascript
复制
示例 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 升汽油。 因此,无论怎样,你都不可能绕环路行驶一周。

解题思路一:暴力破解

从头到尾遍历每个加油站,并检查以该加油站为起点,最终能否行驶一周。

代码语言:javascript
复制
public class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n=gas.length;
        //从第i个加油站出发
        for(int i=0;i<n;i++){
            //到达下一站,油量剩余
            int residue=0;
            //环形下标
            int j=i;
            //一共走了几站
            int k=0;
            while(1==1){
                //当前油量无法到达下一站j+1
                if(residue+gas[j]-cost[j]<0){
                    break;
                }else{
                    //到达下一站j+1后剩余油量
                    residue=residue+gas[j]-cost[j];
                }
                //下一站
                j=(j+1)%n;
                k++;
                if(k>=n){
                    //油量足够达到第n站,即形成环
                    if(residue>=0){
                        return i;
                    }else{
                        break;
                    }
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        Solution solution=new Solution();
        int[] gas  = {2,3,4};
        int[] cost = {3,4,3};
        System.out.println(solution.canCompleteCircuit(gas,cost));
        int[] gas2  = {1,2,3,4,5};
        int[] cost2 = {3,4,5,1,2};
        System.out.println(solution.canCompleteCircuit(gas2,cost2));
        int[] gas3  ={4,5,2,6,5,3};
        int[] cost3 = {3,2,7,3,2,9};
        System.out.println(solution.canCompleteCircuit(gas3,cost3));
    }
}

复杂度分析

时间复杂度:O(N^2),其中 N 为数组的长度。

空间复杂度:O(1)。

解题思路二:一次遍历

我们可以通过减小被检查的加油站数目,来降低总的时间复杂度。

假设我们此前发现,从加油站 x 出发,每经过一个加油站就加一次油(包括起始加油站),最后一个可以到达的加油站是 y(不妨设 x<y)。这就说明:

第一个式子表明无法到达加油站 y的下一个加油站,第二个式子表明可以到达 y以及 y之前的所有加油站。

现在,考虑任意一个位于 x,y之间的加油站 z(包括 x 和 y),我们现在考察从该加油站出发,能否到达加油站 y 的下一个加油站,也就是要判断

​ 之间的大小关系。

根据上面的式子,我们得到:

其中不等式的第二步、第三步分别利用了上面的第一个、第二个不等式。

从上面的推导中,能够得出结论:从 x,y之间的任何一个加油站出发,都无法到达加油站 y 的下一个加油站。

在发现了这一个性质后,算法就很清楚了:我们首先检查第 0 个加油站,并试图判断能否环绕一周;如果不能,就从第一个无法到达的加油站开始继续检查。

代码语言:javascript
复制
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int i = 0;
        while (i < n) {
            int sumOfGas = 0, sumOfCost = 0;
            int cnt = 0;
            while (cnt < n) {
                int j = (i + cnt) % n;
                sumOfGas += gas[j];
                sumOfCost += cost[j];
                if (sumOfCost > sumOfGas) {
                    break;
                }
                cnt++;
            }
            if (cnt == n) {
                return i;
            } else {
                i = i + cnt + 1;
            }
        }
        return -1;
    }
}

复杂度分析

时间复杂度:O(N),其中 N 为数组的长度。我们对数组进行了单次遍历。

空间复杂度:O(1)。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/09/22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目描述
  • 解题思路一:暴力破解
  • 解题思路二:一次遍历
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档