134. Gas Station
Problem Description
You have n gas stations arranged in a circle. Each station i has gas[i] amount of gas available. To travel from station i to the next station (i+1), you need cost[i] amount of gas.
You start with an empty gas tank at one of the stations. Your car has an unlimited capacity gas tank, meaning it can hold any amount of gas.
The goal is to determine if there's a starting station from which you can complete one full circle around all stations. If such a starting point exists, return its index. If it's impossible to complete the circuit, return -1.
Key points:
- The route is circular: after station
n-1, you return to station0 - You must visit all stations exactly once in clockwise order
- You start with 0 gas at your chosen starting station
- At each station, you first fill up with all available gas, then spend the required amount to reach the next station
- The problem guarantees that if a solution exists, it will be unique
For example, if gas = [1,2,3,4,5] and cost = [3,4,5,1,2]:
- Starting from station 3: gain 4 gas, spend 1 to reach station 4 → tank has 3
- At station 4: gain 5 gas, spend 2 to reach station 0 → tank has 6
- At station 0: gain 1 gas, spend 3 to reach station 1 → tank has 4
- At station 1: gain 2 gas, spend 4 to reach station 2 → tank has 2
- At station 2: gain 3 gas, spend 5 to reach station 3 → tank has 0
- Successfully completed the circuit, so return 3
How We Pick the Algorithm
Why Greedy Algorithms?
This problem maps to Greedy Algorithms through a short path in the full flowchart.
If the running tank dips below zero at station i, restart from i+1 — total fuel ≥ total cost guarantees a valid start exists.
Open in FlowchartShow step-by-step reasoning
First, let's pin down the algorithm using the Flowchart. Here's a step-by-step walkthrough:
Is it a graph? Sorted input? kth? Linked list? Hash lookup? Intervals? Partitioning? String segmentation? Small constraints? Subarray?
- No to each: Two parallel arrays around a circular route; we want a single starting index.
Compute a max/min?
- Yes: Among all viable starting stations we want one — equivalent to picking the index that minimizes the running tank deficit.
Sorted index or monotonic answer? Need nearest greater/smaller bounds? Split into subproblems?
- No: No sorted search space, no monotonic stack, and no overlapping subproblems.
Greedy solution?
- Yes: If total
gas - costis non-negative a solution exists, and the optimal start is one past the index where the running tank hits its minimum.
Conclusion: The flowchart leads us to Greedy Algorithms. Sweep once tracking tank and total; whenever tank drops below 0, reset start = i+1 and tank = 0. If total >= 0 at the end, return start; otherwise return -1.
Intuition
The key insight is that if the total gas available is less than the total cost needed, it's impossible to complete the circuit no matter where we start, since the tank always ends up short somewhere. So sum(gas) >= sum(cost) is a necessary condition.
The harder question is which station to start from. Try a candidate starting index start and simulate the trip, tracking a running tank balance equal to gas[i] - cost[i] summed over the stations visited so far. If that balance ever goes negative while driving from start, the car cannot reach the next station - and this failure isn't specific to start. Any station between start and the point of failure would reach that same failing station with even less fuel already collected, so none of them can be a valid start either.
That observation lets us discard the entire failed stretch at once: reset the tank to 0 and try again starting from the very next station. Sweeping through the stations once (with a second pass to confirm a surviving candidate can complete a full lap) finds the answer in O(n) time, without ever stepping backward or tracking two separate pointers.
Solution Approach
The implementation drives around the circle once, restarting the candidate start whenever the tank runs dry.
Initialization:
n = len(gas)
start = None
tank = 0
location = 0
Main Loop:
The loop runs for up to 2 * n steps - one lap to find a candidate start, and a second lap to confirm it can complete the circuit:
while location < n * 2: if start is None: start = location tank += gas[location % n] - cost[location % n] if tank < 0: start = None tank = 0 location += 1 if start is not None and location - start == n: return start % n return -1
At each step, location % n wraps the index around the circle. We add that station's net gas (gas[i] - cost[i]) to tank. If tank drops below 0, the candidate start has failed, so we clear it and let the next iteration pick a fresh one. Once a candidate has survived for exactly n consecutive stations without the tank going negative, it has completed a full lap and is returned.
Example Walkthrough:
Consider gas = [2,3,4] and cost = [3,4,3]:
location = 0:start = 0,tank = 2 - 3 = -1-> negative, resetstart = None,tank = 0location = 1:start = 1,tank = 3 - 4 = -1-> negative, resetstart = None,tank = 0location = 2:start = 2,tank = 4 - 3 = 1location = 3(3 % 3 = 0):tank = 1 + (2 - 3) = 0location = 4(4 % 3 = 1):tank = 0 + (3 - 4) = -1-> negative, resetstart = None,tank = 0location = 5(5 % 3 = 2):start = 5,tank = 4 - 3 = 1
The loop ends at location = 6 without any candidate surviving a full lap of 3 stations, so the function returns -1 - correctly, since sum(gas) = 9 < sum(cost) = 10.
Time Complexity: O(n) - the loop runs at most 2n iterations
Space Complexity: O(1) - only a few variables are tracked
Example Walkthrough
Let's walk through a concrete example with gas = [1,2,3,4,5] and cost = [3,4,5,1,2] (n = 5).
Stations 0-2 each fail immediately:
location = 0:start = 0,tank = 1 - 3 = -2-> negative, resetlocation = 1:start = 1,tank = 2 - 4 = -2-> negative, resetlocation = 2:start = 2,tank = 3 - 5 = -2-> negative, reset
Station 3 becomes the new candidate and holds up:
location = 3:start = 3,tank = 4 - 1 = 3location = 4:tank = 3 + (5 - 2) = 6location = 5(5 % 5 = 0):tank = 6 + (1 - 3) = 4location = 6(6 % 5 = 1):tank = 4 + (2 - 4) = 2location = 7(7 % 5 = 2):tank = 2 + (3 - 5) = 0
At location = 8, location - start = 8 - 3 = 5 = n, so candidate start = 3 has just completed a full lap without the tank ever going negative. The function returns 3 % 5 = 3.
Verification: Starting from station 3 works!
- Station 3: gain 4, spend 1 → balance = 3
- Station 4: gain 5, spend 2 → balance = 6
- Station 0: gain 1, spend 3 → balance = 4
- Station 1: gain 2, spend 4 → balance = 2
- Station 2: gain 3, spend 5 → balance = 0 ✓
The algorithm found station 3 by discarding each failed starting point the moment the tank went negative, rather than checking every possible starting position separately.
Solution Implementation
1class Solution:
2 def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
3 """
4 Find the starting gas station index from which we can complete a circular tour.
5 Sweeps the circle once, restarting the candidate start whenever the tank runs dry.
6
7 Args:
8 gas: List of gas available at each station
9 cost: List of gas cost to travel from station i to station i+1
10
11 Returns:
12 Starting station index if circuit is possible, -1 otherwise
13 """
14 n = len(gas)
15
16 start = None # candidate starting station, None while no candidate is active
17 tank = 0 # running gas balance for the current candidate
18 location = 0 # current station being visited (unwrapped, keeps growing)
19
20 # Simulate up to two full laps: one to find a candidate, one to confirm it
21 while location < n * 2:
22 if start is None:
23 start = location
24
25 tank += gas[location % n] - cost[location % n]
26
27 # This candidate can't make it past this station - discard it
28 if tank < 0:
29 start = None
30 tank = 0
31
32 location += 1
33
34 # The current candidate has survived a full lap - it's the answer
35 if start is not None and location - start == n:
36 return start % n
37
38 return -1
391class Solution {
2 public int canCompleteCircuit(int[] gas, int[] cost) {
3 int n = gas.length;
4
5 int start = -1; // -1 means no active candidate
6 int tank = 0; // running gas balance for the current candidate
7 int location = 0; // current station being visited (unwrapped)
8
9 // Simulate up to two full laps: one to find a candidate, one to confirm it
10 while (location < n * 2) {
11 if (start == -1) {
12 start = location;
13 }
14
15 tank += gas[location % n] - cost[location % n];
16
17 // This candidate can't make it past this station - discard it
18 if (tank < 0) {
19 start = -1;
20 tank = 0;
21 }
22
23 location++;
24
25 // The current candidate has survived a full lap - it's the answer
26 if (start != -1 && location - start == n) {
27 return start % n;
28 }
29 }
30
31 return -1;
32 }
33}
341class Solution {
2public:
3 int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
4 int n = gas.size();
5
6 int start = -1; // -1 means no active candidate
7 int tank = 0; // running gas balance for the current candidate
8 int location = 0; // current station being visited (unwrapped)
9
10 // Simulate up to two full laps: one to find a candidate, one to confirm it
11 while (location < n * 2) {
12 if (start == -1) {
13 start = location;
14 }
15
16 tank += gas[location % n] - cost[location % n];
17
18 // This candidate can't make it past this station - discard it
19 if (tank < 0) {
20 start = -1;
21 tank = 0;
22 }
23
24 location++;
25
26 // The current candidate has survived a full lap - it's the answer
27 if (start != -1 && location - start == n) {
28 return start % n;
29 }
30 }
31
32 return -1;
33 }
34};
351/**
2 * Finds the starting gas station index from which you can complete a circular tour.
3 * Sweeps the circle once, restarting the candidate start whenever the tank runs dry.
4 *
5 * @param gas - Array where gas[i] represents the amount of gas at station i
6 * @param cost - Array where cost[i] represents the gas cost to travel from station i to station i+1
7 * @returns The starting gas station index if the tour is possible, otherwise -1
8 */
9function canCompleteCircuit(gas: number[], cost: number[]): number {
10 const n: number = gas.length;
11
12 let start: number | null = null; // candidate starting station, null while no candidate is active
13 let tank: number = 0; // running gas balance for the current candidate
14 let location: number = 0; // current station being visited (unwrapped)
15
16 // Simulate up to two full laps: one to find a candidate, one to confirm it
17 while (location < n * 2) {
18 if (start === null) {
19 start = location;
20 }
21
22 tank += gas[location % n] - cost[location % n];
23
24 // This candidate can't make it past this station - discard it
25 if (tank < 0) {
26 start = null;
27 tank = 0;
28 }
29
30 location += 1;
31
32 // The current candidate has survived a full lap - it's the answer
33 if (start !== null && location - start === n) {
34 return start % n;
35 }
36 }
37
38 return -1;
39}
40Time and Space Complexity
Time Complexity: O(n)
The loop runs while location < n * 2, and location increments by exactly 1 every iteration starting from 0. So the loop body executes at most 2n times regardless of how many times the candidate start gets reset. Each iteration does a constant amount of work (an addition, a modulo, and a comparison), so the total time is O(2n) = O(n).
Space Complexity: O(1)
The algorithm only tracks a handful of integers - n, start, tank, and location - none of which scale with the input size, giving constant space complexity.
Common Pitfalls
1. Stopping After One Lap Instead of Two
It's tempting to loop only n times, since there are only n stations. But a candidate start found late in the first lap (say at station n - 1) still needs to drive all the way around to confirm it can complete a full circuit. Capping the loop at n instead of n * 2 can return an unconfirmed candidate, or fail to find one that's actually valid.
Problem Code:
while location < n: # too short - a late candidate never gets to prove itself ...
Fix: loop while location < n * 2, and only return once location - start == n - meaning the candidate has survived a full lap of n stations.
2. Adding a Separate sum(gas) < sum(cost) Check
It's common to first check whether sum(gas) < sum(cost) and return -1 immediately, then run the simulation separately. That check is redundant here: if the total gas is less than the total cost, no candidate can ever survive a full lap without the tank going negative, so the loop naturally falls through to return -1 on its own. Adding the extra check doesn't produce a wrong answer, but it's unnecessary work that duplicates what the loop already guarantees.
3. Resetting tank but Forgetting to Reset start
When the tank goes negative, both start and tank need to reset together. Resetting only tank while leaving the old start in place would let a failed starting station keep being credited with stations that come after its failure, producing an incorrect final index:
if tank < 0: tank = 0 # missing: start = None
Since the very next iteration checks if start is None: start = location, forgetting to clear start means that check never fires, and the stale start from the failed attempt gets returned instead of the correct one.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhich of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Want a Structured Path to Master System Design Too? Don’t Miss This!