Gas Station leetcode

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.

這是一道具體問題的題目,brute force的方法比較容易想到,就是從每一個站開始,一直走一圈,累加過程中的淨餘的油量,看它是不是有出現負的,如果有則失敗,從下一個站開始重新再走一圈;如果沒有負的出現,則這個站可以作爲起始點,成功。可以看出每次需要掃描一圈,對每個站都要做一次掃描,所以時間複雜度是O(n^2)。代碼比較直接,這裏就不列舉了。
接下來說說如何提高這個算法。方法主要思想是把這個圈劃分成一個個的負序列,以及一個正序列(如果存在的話)。從任意一個站出發,我們可以累加油的淨餘量,如果出現負的,序列結束,開啓一個新的,並且證明舊的這個序列的起點不能作爲起點,因爲會出現負油量,不能繼續前進。下面我們證明
不僅這個負序列的起點不能作爲起點,負序列中的任意一點都不能作爲起點
證明:
假設我們取定負序列中的一個站作爲起點,因爲一個序列一旦遇到負的淨餘量就會結束並且開啓新的,那麼說明在這個起點前的累加結果必然是正數(否則會結束這個序列,則前面不會是這個序列的一部分)。如此我們從當前序列出發必然會使走到序列終點時負的油量更大,本來已經是負的,所以不能去負序列的任意一個結點作爲起點。
根據上面的劃分方式,我們會把圈分成一段段的序列,而且其中最多隻有一個正序列,那就是繞一圈回到起點的那個序列(當然也有可能整個圈是一個正序列,就是油量一直爲正,那麼我們測的開始點就可以作爲起點了)。接下來我們證明
如果將全部油量累計起來,總量爲正,那麼一定能找到一個起點,使得可以走完一圈,也就是一定有解。
證明:
按照我們之前的劃分,整個圈會被劃分成有累積量爲s1, s2, ..., sk 的負序列,以及一個正序列擁有油量sp(這裏正序列一定存在因爲全部累加和是正的,如果全是負序列那麼結果不會是正的)。而且我們知道s1+s2+...+sk+sp>0,也就是說sp>-s1-s2-...-sk。換句話說,如果我們從sp對應的站的起點出發,在sp對應的序列會一直是正的,並且,當他走到負序列時,因爲sp的正油量大於所有負油量的總和,所以累加油量會一直正,完整整個圈的行駛。這證明了只要累加油量是正的,一定能找到一個起點來完成任務。
根據上面的兩個命題,我們可以來實現代碼,需要維護兩個量,一個是總的累積油量total,另一個是當前序列的累計油量sum,如果出現負的,則切換起點,並且將sum置0。總共是需要掃描所有站一次,時間複雜度是O(n)。而只需要兩個額外變量,空間複雜度是O(1)。代碼如下:

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



發佈了80 篇原創文章 · 獲贊 16 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章