Editorial
Core insight
Gas Station · Greedy Patterns
Core Insight for Gas Station
The transition from the brute force to the optimal solution relies on two key mathematical observations regarding the gas and cost arrays.
Insight 1: Global Feasibility If the total amount of gas available in the entire circuit is less than the total cost to travel the circuit (), it is mathematically impossible to complete the route. We can return -1 immediately. Conversely, if , a solution is guaranteed to exist.
Insight 2: The "Gap" Property This is the critical greedy intuition. Suppose we start at station and can travel successfully up to station , but we fail to reach station (meaning the tank becomes negative at ).
- The Claim: No station between and (where ) can be a valid starting station.
- The Reasoning: When we arrived at station starting from , we had some non-negative amount of gas in the tank (or we would have failed before reaching ). If we were to start a fresh journey at , we would start with 0 gas. Since we failed at with
gas_from_A + gas_accumulated_since_k, we will certainly fail at with onlygas_accumulated_since_k. - Conclusion: If we fail at , the next possible valid start station must be . We can skip all stations from to .
Visual Description:
Imagine plotting the cumulative "net gas" (gas[i] - cost[i]) on a line graph. As you traverse the array, the line goes up when you gain more gas than you spend, and down when you spend more. If the line dips below the x-axis (negative value), that entire segment leading to the dip is invalid as a starting run. The algorithm effectively cuts off these "dipping" segments and restarts the graph at the next index, looking for a segment that stays positive.
Deep dive
Full breakdown
Full reasoning, pitfalls, and implementation flow
LeetCode 134: Gas Station Solution & Explanation
Problem Overview
TL;DR: Iterate through the stations once, tracking the current fuel balance; if the balance drops below zero, the starting point must be after the current station, so reset the start index and clear the current balance.
In the LeetCode 134 Gas Station problem, you are given two integer arrays, gas and cost. gas[i] represents the fuel available at the -th station, and cost[i] represents the fuel required to travel from station to station . The route is circular. Your goal is to find the index of the starting gas station that allows you to traverse the entire circuit once without running out of fuel. If no such station exists, return -1.
This is a classic interview question that tests your ability to optimize a simulation process using greedy logic.
Brute Force Approach for Gas Station
The most intuitive way to solve this is to simulate the journey starting from every single station. We treat every index from to as a potential starting point and attempt to complete the circle.
Naive Algorithm Steps
- Iterate through each station from to .
- For each start station , initialize a
tankvariable to 0. - Use an inner loop to simulate the travel to the next stations (using modulo arithmetic to handle the circular array).
- At each step, update the tank:
tank += gas[current] - cost[current]. - If
tankbecomes negative at any point, break the inner loop (this start index is invalid). - If the inner loop completes steps successfully, return .
Pseudo-code
for start from 0 to n-1:
tank = 0
possible = true
for step from 0 to n-1:
current = (start + step) % n
tank += gas[current] - cost[current]
if tank < 0:
possible = false
break
if possible:
return start
return -1Complexity Analysis
The time complexity is because for every station, we iterate through the entire array in the worst case. With up to , operations result in computations, which far exceeds the standard time limit of roughly operations per second. This approach will result in a Time Limit Exceeded (TLE) error.
Algorithm Strategy: Greedy Patterns
We utilize the insights above to solve the problem in a single pass.
- Track Global Balance: We maintain a
total_surplusvariable that sumsgas[i] - cost[i]for all . This determines if a solution exists at all. - Track Current Segment: We maintain a
current_surplusvariable. As we iterate, we addgas[i] - cost[i]to it. - Greedy Choice: If
current_surplusdrops below 0, it means the current starting point (and any point between the start and the current index) is invalid. - Reset: We reset the starting candidate to
i + 1and resetcurrent_surplusto 0. We do not need to re-check previous stations.
This approach ensures we touch every element exactly once.
Execution Flow
- Initialize
total_surplusto 0. - Initialize
current_surplusto 0. - Initialize
start_indexto 0. - Iterate through the array with index
ifrom0ton-1:- Calculate the net gain at station
i:balance = gas[i] - cost[i]. - Add
balancetototal_surplus. - Add
balancetocurrent_surplus. - Check Constraint: If
current_surplus < 0:- The current path failed. The start cannot be
start_indexor any index up toi. - Update
start_index = i + 1. - Reset
current_surplus = 0(empty tank for the new potential start).
- The current path failed. The start cannot be
- Calculate the net gain at station
- After the loop finishes:
- Check
total_surplus. If it is less than 0, return-1. - Otherwise, return
start_index.
- Check
Proof of Correctness
Claim: If total_surplus >= 0, the start_index identified by the greedy algorithm allows traversal of the full circle.
Proof:
Since total_surplus >= 0, a solution exists. The algorithm sets start_index to . This implies that for any segment ending before , the sum was negative, causing a reset. However, starting from , the current_surplus never dropped below zero until the end of the array (index ).
The remaining question is: can we wrap around from back to ?
Because total_surplus is the sum of the segment and the segment , and we know total_surplus >= 0, the positive surplus accumulated in must be sufficient to offset the negative deficit accumulated in . Therefore, the tank will remain non-negative after wrapping around.
Pattern Reuse Notes
The logic used in the LeetCode 134 Solution is a specific application of greedy accumulation, sharing similarities with:
- Maximum Subarray Sum (Kadane's Algorithm): Kadane's algorithm also resets the current running sum when it drops below zero (or when the current element is greater than the running sum, depending on implementation). Both problems involve finding a valid "segment" in a linear array based on cumulative sums.
Feynman coach · Before you peek at the code
Can you explain the core insight in your own words?
If you can explain it before reading code, you’re far more likely to recall it under interview pressure.
Reference Implementation
C++ Solution for LeetCode 134
1class Solution {
2public:
3 int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
4 int total_surplus = 0;
5 int current_surplus = 0;
6 int start_index = 0;
7
8 for (int i = 0; i < gas.size(); ++i) {
9 int balance = gas[i] - cost[i];
10 total_surplus += balance;
11 current_surplus += balance;
12
13 // If the tank becomes empty, we cannot start at 'start_index'
14 // or any station between 'start_index' and 'i'.
15 if (current_surplus < 0) {
16 current_surplus = 0;
17 start_index = i + 1;
18 }
19 }
20
21 // If total gas is less than total cost, a round trip is impossible.
22 return (total_surplus < 0) ? -1 : start_index;
23 }
24};Java Solution for LeetCode 134
1class Solution {
2 public int canCompleteCircuit(int[] gas, int[] cost) {
3 int totalSurplus = 0;
4 int currentSurplus = 0;
5 int startIndex = 0;
6
7 for (int i = 0; i < gas.length; i++) {
8 int balance = gas[i] - cost[i];
9 totalSurplus += balance;
10 currentSurplus += balance;
11
12 // If current tank drops below zero, the current start point is invalid.
13 // Reset start point to the next station.
14 if (currentSurplus < 0) {
15 currentSurplus = 0;
16 startIndex = i + 1;
17 }
18 }
19
20 // If the total gas provided is less than total cost, return -1
21 return (totalSurplus < 0) ? -1 : startIndex;
22 }
23}Python Solution for LeetCode 134
1class Solution:
2 def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
3 total_surplus = 0
4 current_surplus = 0
5 start_index = 0
6
7 for i in range(len(gas)):
8 balance = gas[i] - cost[i]
9 total_surplus += balance
10 current_surplus += balance
11
12 # If tank goes below zero, the path from start_index to i is invalid
13 if current_surplus < 0:
14 current_surplus = 0
15 start_index = i + 1
16
17 # If total gas available < total gas required, impossible to complete circuit
18 return start_index if total_surplus >= 0 else -1