客戶的一個緊急bug,我用了兩種方式進行 C# 反編譯修改原始碼
阿新 • • 發佈:2020-11-17
LeetCode 134 加油站
https://leetcode-cn.com/problems/gas-station/
法一 直接模擬
從頭到尾遍歷每個加油站,檢查以該加油站為起點,最終能否繞行一圈。
class Solution { public: int canCompleteCircuit(vector<int>& gas, vector<int>& cost) { int sz = gas.size(); for (int start = 0; start < sz; ++start) { if (gas[start] < cost[start]) continue; int v = gas[start]; // 剩餘汽油量 int j = (start + 1) % sz; // 指向下一個要到達的站點 while (j != start) { // 到達站點j並加油後的剩餘汽油量 v = v - cost[(j - 1 + sz) % sz] + gas[j]; // 如果無法達到下一個(j+1)個站點 if (v < cost[j]) break; j = (j + 1) % sz; } if (j == start) return start; } return -1; } };
法二 一次遍歷
我們嘗試對上面的法一進行加速。假設從站點\(x\)出發,每經過一個加油站就加一次油,第一個無法到達的站點是\(y\)(力扣官方題解上應該是有誤,如果第一個無法到達的站點是\(y\),那麼下面公式的上標只能取到\(y-1\),而不是\(y\)),則有以下公式成立:
\[\sum_{i = x}^{y-1} gas[i] \lt \sum_{i = x}^{y-1} cost[i] \]\[\sum_{i = x}^j gas[i] >= \sum_{i = x}^{j}cost[i], x \le j \le y - 2 \]第一個式子表示無法到達站點\(y\),第二個式子表明可以到達\(y\)
以上公式說明從\(x, y\)之間的任何一個站點出發,都無法到達站點\(y\)。既然如此,我們首先檢查第0個加油站,並試圖找到第一個無法到達的加油站\(z\)。如果能找到,下一次就從加油站\(z + 1\)開始檢查。最終,我們只遍歷了原陣列一次。時間複雜度降到了\(O(N)\)
程式碼如下:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int sz = gas.size();
int start = 0;
while (start < sz) {
// 從起始位置開始往前移動
int skip = 0;
int sumOfGas = 0, sumOfCost = 0;
while (skip < sz) {
int z = (start + skip) % sz;
sumOfGas += gas[z];
sumOfCost += cost[z];
// 如果找到了第一個無法到達的站點x則退出
if (sumOfCost > sumOfGas) break;
++skip;
}
// 如果剛好繞了一圈回到了起點則返回起點位置下標
if (skip == sz) return start;
// 否則將起始位置調整為x + 1
start += (skip + 1);
}
return -1;
}
};