Facebook Pixel

134. Gas Station

MediumGreedyArray
LeetCode ↗

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 station 0
  • 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
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Greedy Algorithms?

This problem maps to Greedy Algorithms through a short path in the full flowchart.

Compute amax/min?yesGreedysolution?yesGreedyAlgorithms

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 Flowchart
Show 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 - cost is 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, reset start = None, tank = 0
  • location = 1: start = 1, tank = 3 - 4 = -1 -> negative, reset start = None, tank = 0
  • location = 2: start = 2, tank = 4 - 3 = 1
  • location = 3 (3 % 3 = 0): tank = 1 + (2 - 3) = 0
  • location = 4 (4 % 3 = 1): tank = 0 + (3 - 4) = -1 -> negative, reset start = None, tank = 0
  • location = 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, reset
  • location = 1: start = 1, tank = 2 - 4 = -2 -> negative, reset
  • location = 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 = 3
  • location = 4: tank = 3 + (5 - 2) = 6
  • location = 5 (5 % 5 = 0): tank = 6 + (1 - 3) = 4
  • location = 6 (6 % 5 = 1): tank = 4 + (2 - 4) = 2
  • location = 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
39
1class 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}
34
1class 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};
35
1/**
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}
40

Time 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 Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More