首页 > 代码库 > [C++]LeetCode: 119 Gas Station

[C++]LeetCode: 119 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.

思路:这道题乍看不是很难,最开始想到的办法就是一个点一个点计算,计算到没油了,证明这个点不能做出发点,移动到下一个点出发,继续重复计算。这个思路简答,但是编译超时。而且还需要处理环的问题。

LTE Code:

class Solution {
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        if(gas.size() == 0) return -1;
        int len = gas.size();
        
        for(int i = 0; i < len; i++)
        {
            int gascapcity = gas[i] - cost[i];
            
            int j = (i+1) % len;
            while(gascapcity >= 0)
            {
                if(j == i) return i;
                gascapcity = gascapcity + gas[j] - cost[j];
                j = (j+1) % len;
            }
        }
        return -1;
    }
};

Answer 1: 

思路:为了解决环的问题,我们将出发点start设在数组末尾,结束点end设为数组头,在start 未和end相遇前,我们进行操作,如果油的总和一直大于等于0,我们移动end++,如果小于0,我们移动start--, 并且加上此时的剩余量gas[newstart] - cost[newstart],需要注意的是,我们是在之前统计的sum基础上相加(即加上newstart 到end之间的累积量)。因为之后的求和我们是从end之后开始计算的,这段的累积量不能忘记, 之后我们不会重复计算。如果最后开始点和终止点相遇时,sum >= 0返回start, 如果小于0,说明我们不能完成任务,返回-1.

AC Code:

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];  //需要加上newstart到end之间的累积量,因为end是从数组头开始计算的,符号是+= 即sum = sum + gas[start]-cost[start];
            }
        }
        return sum >= 0 ? start : -1;
        
    }
};

Answer 2:

思路:我们总结出以下两个属性:相关的证明可以看:LeetCode Gas Station

1.如果总的gas - cost小于零的话,那么无解返回-1

2.如果前面所有的gas - cost加起来小于0,那么前面所有的点都不能作为出发点。

因此我们只需要遍历一次,维护三个变量,start表示起点,如果一旦不满足从该起点到此处所有点都不能作为出发点,tank表示从新起点开始,统计的油的积累量,total表示从0开始到最后统计的起点前,欠缺的油的量。如果total + tank >=0, 说明任务能完成,否则不行。

AC Code:

class Solution {
public:
    int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
        int start = 0;
        int total = 0;
        int tank = 0;
        
        for(int i = 0; i < gas.size(); i++)
        {
            if((tank += gas[i] - cost[i]) < 0)
            {
                start = i + 1;
                total += tank;
                tank = 0;
            }
        }
        return (total + tank >= 0) ? start : -1;
        
    }
};

这种题目,还是比较考查我们处理问题的能力。规律可能很难快速发现,最好的办法,就是先举些例子,观察他们的特性,然后总结出来,再设计合适的算法。




[C++]LeetCode: 119 Gas Station