LeetCode | 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 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.

题目解析:

方案一:

两个数组之间的值是对应的,那么就将gas[i]-cost[i]经过i结点增加或消耗的油量。这样就直接考虑结点的值,而不用考虑路程中的值,进一步转化成一个一维数组,求从哪一点开始求和,能无负数出现。

常规思维是,让任一点为起始点,开始计算,这样时间复杂度为O(N^2)。但是负数的起始点是不可能的,因此跳过负数为起始的。更进一步,我们选那些s[i-1]为负数,s[i]为大于等于0时,i为起始点,即使i后有连续几个为正数,由于题目中结果唯一,则必须i开始为起始点。这样就更进一步简化。不过实现的时候,有点复杂,我只是选择非负数为起始点,进行递归求解。

如果Judge为false时,才判断深层次的递归返回值。

class Solution {
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        if(gas.size() != cost.size())
            return -1;
        res = -1;
        vector<int> remainder;
        for(int i = 0;i < gas.size();i++)
            remainder.push_back(gas[i]-cost[i]);
        FindIndex(remainder,0);
        return res;
    }
    bool FindIndex(vector<int> &remainder,int index){
        if(index >= remainder.size()){
            return false;
        }
        int i;//写在外面
        for(i = index;i < remainder.size();i++){
            if(remainder[i] >= 0)   //要加等号[2] [2]
                break;
        }
        if(i == remainder.size()){
            int res = -1;
            return false;
        }

        return Judge(remainder,i) || FindIndex(remainder,i+1);
    }
    bool Judge(vector<int> &remainder,int index){
        int sum = 0;
        for(int i = 0;i < remainder.size();i++){
            sum += remainder[(index+i)%remainder.size()];
            if(sum < 0)
                return false;
        }
        res = index;
        return true;
    }
private:
    int res;
};

方案二:

线性时间复杂度O(n)

我们让i=0…n-1开始遍历,期间统计求和sum,如果sum为负数,则肯定从i+1之后开始!所以当j从i+1…n-1后sum始终保持非负数, 就无序验证n个数的和是否一定为正数。这也跟题目有关,保证了有唯一解。

class Solution {
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int sum=0;
        int total=0;
        int start=0;
        for(int i=0;i<gas.size();i++)
        {
            sum+=gas[i]-cost[i];
            total+=gas[i]-cost[i];
            if(sum < 0)
            {
                start=(i+1)%gas.size(); sum=0;
            }
        }
        
        if(total <0)
            return -1;
        else
            return start;
    }
};

方案三:

以某一结点为起始点i=begin,然后i++,如果sum为负数了,就begin–,并sum+s[begin];当sum再为负数了,就begin–…..这样求解的话,也为线性时间复杂度。

解题思路:
1:假设出发车站为0,初始化车内油量0
2:车内油量=车站油量-消耗
3:如果车内油量大于0,车开到下一车站,否则出发车站前移一个车站
重复2,3步,直到所有车站遍历完。如果车内油量剩余大于等于0,返回出发车站,否则返回-1.

public int canCompleteCircuit(int[] gas, int[] cost) {
		if (gas == null) {
			return -1;
		}
        // Note: The Solution object is instantiated only once and is reused by each test case.
		int count = gas.length;
		
		int n = 0;
		int gasInCar = 0;
		int begin = 0;
		int end = 0;
		int i = 0;
		while (n < count - 1) {
			gasInCar += gas[i] - cost[i];
			if (gasInCar >=0) {//forward
				end++;
				i=end;
			} else {
				begin--;
				if (begin < 0) {
					begin = count - 1;
				}
				i = begin;
			}
			
			n++;
		}
		
		gasInCar += gas[i] - cost[i];
		
		if (gasInCar >= 0) {
			return begin;
		} else {
			return -1;
		}
		
    }

点赞