134. Gas Station - Explanation
Description
There are n gas stations along a circular route. You are given two integer arrays gas and cost where:
gas[i]is the amount of gas at theithstation.cost[i]is the amount of gas needed to travel from theithstation to the(i + 1)thstation. (The last station is connected to the first station)
You have a car that can store an unlimited amount of gas, but you begin the journey with an empty tank at one of the gas stations.
Return the starting gas station's index such that you can travel around the circuit once in the clockwise direction. If it's impossible, then return -1.
It's guaranteed that at most one solution exists.
Example 1:
Input: gas = [1,2,3,4], cost = [2,2,4,1]
Output: 3Explanation: Start at station 3 and fill up with gas[3] = 4, so tank = 4.
Travel from station 3 to station 0, spending cost[3] = 1, then fill gas[0] = 1, so tank = 4 - 1 + 1 = 4.
Travel from station 0 to station 1, spending cost[0] = 2, then fill gas[1] = 2, so tank = 4 - 2 + 2 = 4.
Travel from station 1 to station 2, spending cost[1] = 2, then fill gas[2] = 3, so tank = 4 - 2 + 3 = 5.
Travel from station 2 back to station 3, spending cost[2] = 4, so tank = 5 - 4 = 1.
The circuit is complete, so return 3.
Example 2:
Input: gas = [1,2,3], cost = [2,3,2]
Output: -1Explanation:
You cannot start at station 0 or 1 because neither has enough gas to travel to the next station.
If you start at station 2, fill gas[2] = 3, so tank = 3.
Travel from station 2 to station 0, spending cost[2] = 2, then fill gas[0] = 1, so tank = 3 - 2 + 1 = 2.
Travel from station 0 to station 1, spending cost[0] = 2, then fill gas[1] = 2, so tank = 2 - 2 + 2 = 2.
To travel from station 1 to station 2, you need cost[1] = 3 gas, but the tank only has 2.
So no starting station can complete the circuit, and the answer is -1.
Constraints:
1 <= gas.length == cost.length <= 10000 <= gas[i], cost[i] <= 1000
Topics
Recommended Time & Space Complexity
You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array.
Hint 1
A brute force approach would be to start at each gas station, simulate the process, and return the index where completing the circuit is possible. This would be an O(n^2) time solution. Can you think of a better way? Maybe a greedy approach works.
Hint 2
We can immediately return -1 if sum(gas) < sum(cost), as completing the circuit is impossible due to insufficient gas. Otherwise, a solution always exists because the total gas is sufficient to cover the total cost, meaning there must be a valid starting point that allows completing the circuit.
Hint 3
We start with a variable total to track the gas balance and initialize the result index to 0. As we iterate through the array with index i, we accumulate the difference (gas[i] - cost[i]). If total becomes negative at any index, we reset it to 0 and update the result index to (i + 1).
Prerequisites
Before attempting this problem, you should be comfortable with:
- Greedy Algorithms - Recognizing when local decisions can determine global validity
- Array Traversal - Iterating through arrays while maintaining running totals
- Two Pointers - Using pointers from opposite ends to efficiently narrow down candidates
- Circular Array Handling - Working with wrap-around indices using modular arithmetic
1. Brute Force
Intuition
We need to find a starting gas station index such that we can travel around the entire circle exactly once without the gas tank ever going negative.
The most direct (brute force) idea is:
- try starting from every station
i - simulate the trip around the circle
- if at any point the tank becomes negative, that start index fails
- if we return back to
isuccessfully, theniis a valid answer
At each station:
- we gain
gas[j] - we spend
cost[j]to travel to the next station
So the tank changes bygas[j] - cost[j].
Algorithm
- Let
nbe the number of stations. - For each possible starting station
ifrom0ton - 1:- Initialize
tank = gas[i] - cost[i] - If
tank < 0, we cannot even leave stationi, so skip it
- Initialize
- Set
jto the next station(i + 1) % n - While we haven’t returned to
i:- Add gas at station
j:tank += gas[j] - Subtract travel cost to next station:
tank -= cost[j] - If
tank < 0, this startifails, stop the simulation - Move
jto(j + 1) % n
- Add gas at station
- If we successfully return to
i(completed the circle):- Return
i
- Return
- If no starting index works:
- Return
-1
- Return
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
n = len(gas)
for i in range(n):
tank = gas[i] - cost[i]
if tank < 0:
continue
j = (i + 1) % n
while j != i:
tank += gas[j]
tank -= cost[j]
if tank < 0:
break
j += 1
j %= n
if j == i:
return i
return -1Time & Space Complexity
- Time complexity:
- Space complexity:
2. Two Pointers
Intuition
We need to find a gas station index from which we can complete the full circular route without the gas tank ever becoming negative.
Instead of simulating the trip from every station (brute force), this approach uses two pointers to narrow down the possible starting station efficiently.
Think of the route as a circle that we are trying to “cover” from both ends:
startmoves backward from the end of the arrayendmoves forward from the beginning of the arraytankkeeps track of the current gas balance for the segment we are considering
At every step, we decide which side to expand based on whether the current tank is sufficient:
- If the
tankis negative, the current segment cannot work, so we must include more gas by movingstartbackward - If the
tankis non-negative, we can safely extend the route forward by movingend
By doing this, we gradually merge the segment until start meets end.
If the final tank is non-negative, start is a valid starting station.
Algorithm
- Let
nbe the number of gas stations. - Initialize two pointers:
start = n - 1end = 0
- Initialize
tankwith the net gas atstart:tank = gas[start] - cost[start]
- While
start > end:- If
tank < 0:- Move
startone step backward - Add the net gas of the new
startstation totank
- Move
- Else:
- Extend the route forward by including station
end - Add
gas[end] - cost[end]totank - Move
endone step forward
- Extend the route forward by including station
- If
- After the loop ends, all stations are included in the segment
- If
tank >= 0, returnstartas the valid starting index. - Otherwise, return
-1.
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
n = len(gas)
start, end = n - 1, 0
tank = gas[start] - cost[start]
while start > end:
if tank < 0:
start -= 1
tank += gas[start] - cost[start]
else:
tank += gas[end] - cost[end]
end += 1
return start if tank >= 0 else -1Time & Space Complexity
- Time complexity:
- Space complexity:
3. Greedy
Intuition
We want to find a gas station index from which we can complete the entire circular route without the gas tank ever going negative.
First, notice an important fact:
- If the total gas available is less than the total cost required, then it is impossible to complete the circuit from any station.
If the total gas is sufficient, then there must be exactly one valid starting station.
The greedy idea is to scan the stations from left to right while keeping track of the current tank balance.
- If at some index the tank becomes negative, it means we cannot start from any station between the previous start and this index, because they would all run out of gas at the same point.
- So we reset the tank and try the next station as a new starting point.
Algorithm
- Check if the total gas is less than the total cost:
- If
sum(gas) < sum(cost), return-1immediately.
- If
- Initialize:
total = 0to track the current gas balance.res = 0to store the candidate starting index.
- Iterate through all stations from index
0ton - 1. - At each station
i:- Add the net gas change:
total += gas[i] - cost[i]
- Add the net gas change:
- If
totalbecomes negative:- The current starting point cannot work.
- Reset
total = 0. - Set the next station as the new candidate start:
res = i + 1.
- After finishing the loop:
- Return
resas the valid starting station.
- Return
Time & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Forgetting to Check Total Gas vs Total Cost First
The greedy solution assumes a valid starting point exists if total gas is sufficient. However, skipping this global check can cause returning an invalid index when no solution exists. Always verify sum(gas) >= sum(cost) before applying the greedy logic, or the algorithm may return a false positive starting index.
Resetting to an Invalid Starting Index
When the running tank goes negative at index i, the new candidate start should be i + 1. A common mistake is setting it to i, which is guaranteed to fail since we just proved the journey fails at that point. Additionally, when i + 1 equals n, there's no valid start, but this is handled by the total gas check.
Not Understanding Why Failed Stations Can Be Skipped
The greedy approach skips all stations between the previous start and the failing point. This works because if we cannot reach station j starting from station i, we also cannot reach j starting from any station between i and j. Those intermediate stations have strictly less accumulated gas when reaching j. Understanding this principle is key to trusting the linear-time solution.
Sign in to join the discussion