Homeβ€Ί DSAβ€Ί Gas Station Problem β€” Greedy Circular Tour

Gas Station Problem β€” Greedy Circular Tour

Where developers are forged. Β· Structured learning Β· Free forever.
πŸ“ Part of: Greedy & Backtracking β†’ Topic 13 of 13
Solve the Gas Station problem using a greedy algorithm.
βš™οΈ Intermediate β€” basic DSA knowledge assumed
In this tutorial, you'll learn:
  • If total gas β‰₯ total cost, exactly one valid starting station exists.
  • Track cumulative surplus; when it goes negative, reset start to next station.
  • O(n) time, O(1) space β€” single pass.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
⚑ Quick Answer
Imagine petrol stations arranged in a circle. Each station gives you some fuel, and it costs fuel to drive to the next station. You start empty. Which station should you start from to complete the full circle without running out? The greedy insight: if you run out at station k, don't start from any station between start and k β€” you would have run out even sooner starting from them.

The gas station problem is LeetCode 134 and a canonical example of a greedy algorithm with a non-obvious correctness proof. The O(n) solution looks almost too simple β€” one pass, tracking two sums β€” but the proof of why it works is the important part.

The key insight, once you see it, is unforgettable: if you start at station S and fail at station K, then no station between S and K can be a valid starting point. They would all fail at K too, having less fuel at that point than S did. This single observation collapses what looks like an O(n^2) search into a single linear pass.

O(n) Greedy Solution

Key insight: if the total gas β‰₯ total cost, a solution always exists. To find it: track current tank. If tank goes negative, the current start is invalid β€” reset start to next station and reset tank.

gas_station.py Β· PYTHON
12345678910111213141516
def can_complete_circuit(gas: list[int], cost: list[int]) -> int:
    total_surplus = 0
    current_surplus = 0
    start = 0
    for i in range(len(gas)):
        diff = gas[i] - cost[i]
        total_surplus += diff
        current_surplus += diff
        if current_surplus < 0:
            # Can't start from any station 0..i
            start = i + 1
            current_surplus = 0
    return start if total_surplus >= 0 else -1

print(can_complete_circuit([1,2,3,4,5], [3,4,5,1,2]))  # 3
print(can_complete_circuit([2,3,4],     [3,4,3]))        # -1
β–Ά Output
3
-1

Why the Greedy Works

Two key observations:

  1. If total gas β‰₯ total cost, a solution exists. The sum of all surpluses is non-negative, so there must be some starting point where cumulative sum never goes negative.
  1. If starting from S, you run out at station k, then no station between S and k works as a start. Proof: if you could start from some S' between S and k, then starting from S (which has non-negative surplus from S to S') would also work from S' β€” but we know you run out at k. Contradiction. So S' is also invalid.

This means once we reset start to i+1, all previous starts are definitively ruled out.

πŸ”₯
Key InvariantAt any point where we reset start to i+1, the current_surplus is negative. This means stations 0 through i have already collectively 'used up' whatever buffer existed β€” no subset starting point among them can succeed.

Worked Example

gas = [1, 2, 3, 4, 5] cost = [3, 4, 5, 1, 2] diff = [-2,-2,-2, 3, 3]

i=0: surplus=-2 < 0 β†’ start=1, surplus=0 i=1: surplus=-2 < 0 β†’ start=2, surplus=0 i=2: surplus=-2 < 0 β†’ start=3, surplus=0 i=3: surplus=+3 β†’ start still 3 i=4: surplus=+3+3=6 β†’ start still 3 total_surplus = -2-2-2+3+3 = 0 β‰₯ 0 β†’ return start=3 βœ“

Verify: start at 3 with 0 fuel. - Station 3: +4, -1 = 3 remaining. Drive to 4. - Station 4: +5, -2 = 6. Drive to 0. - Station 0: +1, -3 = 4. Drive to 1. - Station 1: +2, -4 = 2. Drive to 2. - Station 2: +3, -5 = 0. Back to start. βœ“

🎯 Key Takeaways

  • If total gas β‰₯ total cost, exactly one valid starting station exists.
  • Track cumulative surplus; when it goes negative, reset start to next station.
  • O(n) time, O(1) space β€” single pass.
  • The greedy works because a failed start rules out all intermediate stations as potential starts.
  • Total surplus β‰₯ 0 is both necessary and sufficient for a solution to exist.

Interview Questions on This Topic

  • QWhy does resetting start to i+1 when surplus goes negative always give the correct answer?
  • QProve that if total gas β‰₯ total cost, a valid starting station always exists.
  • QWhat is the time and space complexity of the greedy gas station solution?
  • QCan there be more than one valid starting station? Why or why not?

Frequently Asked Questions

Is there a case with exactly one valid start vs multiple valid starts?

When a solution exists, it is unique. If there were two valid starting stations, you could start from one, reach the other with positive fuel, continue the circuit, and return β€” implying surplus at both points, but that leads to a contradiction in the balance.

πŸ”₯
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousInterval Scheduling and Meeting Rooms Problem
Forged with πŸ”₯ at TheCodeForge.io β€” Where Developers Are Forged