【LeetCode-面试算法经典-Java实现】【134-Gas Station(加油站问题)】

【134-Gas Station(加油站问题】


【LeetCode-面试算法经典-Java实现】【所有题目目录索引】

原题

  There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

  You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station’s index if you can travel around the circuit once, otherwise return -1.

  Note:

  The solution is guaranteed to be unique.

题目大意

  沿环形路线有N个加油站,其中气体在车站i是量是gas[i]。你有车有无限容量的气罐,从加油站i到下一个加油站站点i+1,要消耗cost[i]的气体。你开始旅程时,气罐是空的。回到起始加油站的指数,选择一个起点开始旅游,如果你能在周围环形旅行一次,就返回开始的加油站索引,否则返回-1。

  注意: 答案保证是唯一的。

解题思路

  假设从站点 i 出发,到达站点 k 之前,依然能保证油箱里油没见底儿,从k 出发后,见底儿了。那么就说明 diff[i] + diff[i+1] + … + diff[k] < 0,而除掉diff[k]以外,从diff[i]开始的累加都是 >= 0的。也就是说diff[i] 也是 >= 0的,这个时候我们还有必要从站点 i + 1尝试吗?仔细一想就知道:车要是从站点 i+1出发,到达站点k后,甚至还没到站点k,油箱就见底儿了,因为少加了站点 i 的油。。。

  因此,当我们发现到达k 站点邮箱见底儿后,i 到 k 这些站点都不用作为出发点来试验了,肯定不满足条件,只需要从k+1站点尝试即可!因此解法时间复杂度从O(n2)降到了 O(2n)。之所以是O(2n),是因为将k+1站作为始发站,车得绕圈开回k,来验证k+1是否满足。

  等等,真的需要这样吗?

  我们模拟一下过程:

  a. 最开始,站点0是始发站,假设车开出站点p后,油箱空了,假设sum1 = diff[0] +diff[1] + … + diff[p],可知sum1 < 0;

  b. 根据上面的论述,我们将p+1作为始发站,开出q站后,油箱又空了, 设sum2 = diff[p+1] +diff[p+2] + … + diff[q],可知sum2 < 0。

  c. 将q+1作为始发站,假设一直开到了未循环的最末站,油箱没见底儿,设sum3 = diff[q+1] +diff[q+2] + … + diff[size-1],可知sum3 >= 0。

  要想知道车能否开回 q 站,其实就是在sum3 的基础上,依次加上 diff[0] 到 diff[q],看看sum3在这个过程中是否会小于0。但是我们之前已经知道 diff[0] 到 diff[p-1] 这段路,油箱能一直保持非负,因此我们只要算算sum3 + sum1是否 <0,就知道能不能开到 p+1站了。

  如果能从p+1站开出,只要算算sum3 + sum1 + sum2 是否 < 0,就知都能不能开回q站了。

  因为 sum1, sum2 都 < 0,因此如果 sum3 + sum1 + sum2 >=0 那么sum3 + sum1 必然 >= 0,也就是说,只要sum3 + sum1 + sum2 >=0,车必然能开回q站。而sum3 + sum1 + sum2 其实就是 diff数组的总和 Total,遍历完所有元素已经算出来了。

  因此 Total 能否 >= 0,就是是否存在这样的站点的 充分必要条件。

  这样时间复杂度进一步从O(2n)降到了 O(n)。

代码实现

算法实现类

public class Solution {

    public int canCompleteCircuit(int[] gas, int[] cost) {
        // 参数检验
        if (gas == null || cost == null || gas.length == 0 || gas.length != cost.length) {
            return -1;
        }

        // 记录访问的起始点
        int start = 0;
        // 加的气和消耗的气的总差值
        int total = 0;
        // 从start位置开始,加的气和消耗的气的总差值
        int sum = 0;

        for (int i = 0; i < gas.length; i++) {
            total += (gas[i] - cost[i]);

            // 如是油箱没有油了
            if (sum < 0) {
                // 重新设置油箱中的油
                sum = gas[i] - cost[i];
                // 记录新的起点位置
                start = i;
            } else {
                // 油箱中还有油,更新油箱中的油数
                sum += (gas[i] - cost[i]);
            }
        }

        return total >= 0 ? start : -1;
    }

    // 下面的方法会超时O(N^2)时间复杂度
    public int canCompleteCircuit2(int[] gas, int[] cost) {
        // 参数检验
        if (gas == null || cost == null || gas.length == 0 || gas.length != cost.length) {
            return -1;
        }

        // 剩下的气体,开始时为0
        int leftGas = 0;
        // 开始出发的站点
        int start = 0;
        // 结束的站点
        int end = 1;

        // 未走一周
        while (start < gas.length) {

            // 到达下一个站后的气体简便量
            leftGas = gas[start] - cost[start];

            // 可以走到下一个站
            if (leftGas > 0) {
                // 记录下一个站
                end = (start + 1) % gas.length;

                // 如果一直可以到下一个站就持续进行操作
                while (start != end && (leftGas += (gas[end] - cost[end])) >= 0) {
                    end = (end + 1) % gas.length;
                }

                // 说明已经遍历了一周
                if (start == end) {
                    return start;
                }
            }

            start++;
        }

        return -1;
    }
}

评测结果

  点击图片,鼠标不释放,拖动一段位置,释放后在新的窗口中查看完整图片。

特别说明

欢迎转载,转载请注明出处【http://blog.csdn.net/derrantcm/article/details/47678215

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-26 17:54:21

【LeetCode-面试算法经典-Java实现】【134-Gas Station(加油站问题)】的相关文章

[leetcode]134. Gas Station加油站

There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an e

134 Gas Station 加油站

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油gas[i].你有一辆油箱容量无限的的汽车,从第 i 个加油站前往第 i+1 个加油站需要消耗汽油 cost[i].你从其中一个加油站出发,开始时油箱为空.如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回-1.注意:给定的数据可保证答案是唯一的.详见:https://leetcode.com/problems/gas-station/description/ class Solution { public: int canCom

【LeetCode-面试算法经典-Java实现】【139-Word Break(单词拆分)】

[139-Word Break(单词拆分)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words. For example, given s = "leetcode", di

【LeetCode-面试算法经典-Java实现】【107-Binary Tree Level Order Traversal II(二叉树层序遍历II)】

[107-Binary Tree Level Order Traversal II(二叉树层序遍历II)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). For example

【LeetCode-面试算法经典-Java实现】【064-Minimum Path Sum(最小路径和)】

[064-Minimum Path Sum(最小路径和)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. Note: You can only move either

【LeetCode-面试算法经典-Java实现】【056-Merge Intervals(区间合并)】

[056-Merge Intervals(区间合并)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a collection of intervals, merge all overlapping intervals. For example, Given [1,3],[2,6],[8,10],[15,18], return [1,6],[8,10],[15,18]. 题目大意 给定一个区间集合,合并有重叠的区间. 解题思路 先对区间进行排序.按開始

【LeetCode-面试算法经典-Java实现】【066-Plus One(加一)】

[066-Plus One(加一)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a non-negative number represented as an array of digits, plus one to the number. The digits are stored such that the most significant digit is at the head of the list. 题目大意 给定一个用数组表示的一个数,

【LeetCode-面试算法经典-Java实现】【067-Add Binary(二进制加法)】

[067-Add Binary(二进制加法)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given two binary strings, return their sum (also a binary string). For example, a = "11" b = "1" Return "100" 题目大意 给定两个二进制的字符串,返回它们的和,也是二进行制字符串. 解题思路 先将对应的两个二进制字符串

【LeetCode-面试算法经典-Java实现】【054-Spiral Matrix(螺旋矩阵)】

[054-Spiral Matrix(螺旋矩阵)] [LeetCode-面试算法经典-Java实现][全部题目文件夹索引] 原题 Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. For example, Given the following matrix: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ]