title: Gas Station
slug: gas-station
difficulty: medium
leetcode_id: 134
leetcode_url: https://leetcode.com/problems/gas-station/
categories:
  - arrays
patterns:
  - greedy

description: |
  There are `n` gas stations along a circular route, where the amount of gas at the i<sup>th</sup> station is `gas[i]`.

  You have a car with an unlimited gas tank and it costs `cost[i]` of gas to travel from the i<sup>th</sup> station to its next (i + 1)<sup>th</sup> station. You begin the journey with an empty tank at one of the gas stations.

  Given two integer arrays `gas` and `cost`, return *the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return* `-1`. If there exists a solution, it is **guaranteed** to be **unique**.

constraints: |
  - `n == gas.length == cost.length`
  - `1 <= n <= 10^5`
  - `0 <= gas[i], cost[i] <= 10^4`
  - The input is generated such that the answer is unique

examples:
  - input: "gas = [1,2,3,4,5], cost = [3,4,5,1,2]"
    output: "3"
    explanation: "Start at station 3 (index 3) and fill up with 4 units of gas. Your tank = 0 + 4 = 4. Travel to station 4: tank = 4 - 1 + 5 = 8. Travel to station 0: tank = 8 - 2 + 1 = 7. Travel to station 1: tank = 7 - 3 + 2 = 6. Travel to station 2: tank = 6 - 4 + 3 = 5. Travel to station 3: cost is 5, gas is just enough. Return 3."
  - input: "gas = [2,3,4], cost = [3,4,3]"
    output: "-1"
    explanation: "Starting from any station, you cannot complete the circuit. For example, starting at station 2 with 4 gas, you can reach station 1 but cannot travel back to station 2 (requires 4 gas, you only have 3)."

explanation:
  intuition: |
    Imagine you're planning a road trip around a circular route with gas stations. At each station, you can fill up some gas, but travelling to the next station costs some gas. The question is: **can you find a starting point where you never run out of fuel?**

    The key insight comes from two observations:

    **Observation 1: Total gas must be enough.** If the total gas available across all stations is less than the total cost to travel the entire circuit, it's impossible to complete the trip from *any* starting point. Conversely, if total gas >= total cost, a solution is **guaranteed** to exist.

    **Observation 2: If you fail at station `j`, skip all previous candidates.** Suppose you start at station `i` and run out of gas at station `j`. You might think: "Maybe I should try starting at `i+1`?" But here's the crucial insight — if you couldn't reach `j` starting from `i` with a full journey's worth of gas from stations `i` to `j-1`, then starting from any station *between* `i` and `j` would give you even *less* gas (you'd miss the contributions from earlier stations). So **all stations from `i` to `j` are invalid starting points**.

    This means when we fail, we can jump our candidate start directly to `j+1`, making this a linear-time algorithm.

  approach: |
    We solve this using a **Single Pass Greedy Approach**:

    **Step 1: Initialise tracking variables**

    - `total_tank`: Tracks the cumulative surplus/deficit across all stations (used to check if a solution exists)
    - `current_tank`: Tracks the current fuel level from our candidate starting point
    - `start_station`: The index of our current candidate starting point, initialised to `0`

    &nbsp;

    **Step 2: Iterate through each station**

    - For each station `i`, calculate `gas[i] - cost[i]` (the net gain/loss at this station)
    - Add this value to both `total_tank` and `current_tank`
    - If `current_tank` becomes negative, it means we can't reach station `i+1` from our current `start_station`
    - When this happens, reset `start_station` to `i+1` and reset `current_tank` to `0`

    &nbsp;

    **Step 3: Check feasibility and return**

    - After the loop, if `total_tank >= 0`, a solution exists and `start_station` is our answer
    - If `total_tank < 0`, return `-1` (not enough total gas)

    &nbsp;

    The greedy choice — skipping all stations between our failed start and the failure point — is valid because those intermediate stations would only give us less fuel to work with.

  common_pitfalls:
    - title: Trying Every Starting Point
      description: |
        A brute force approach would try starting at each station and simulate the entire trip:
        - For each starting station `i`, simulate travelling all `n` stations
        - Check if the tank ever goes negative

        This results in **O(n^2) time complexity**. With `n` up to `10^5`, this means up to 10 billion operations — a guaranteed **Time Limit Exceeded (TLE)**.
      wrong_approach: "Nested loops simulating from each start"
      correct_approach: "Single pass with smart candidate elimination"

    - title: Not Understanding Why We Can Skip Stations
      description: |
        When you fail at station `j` starting from station `i`, it might seem wasteful to skip directly to `j+1`. Why not try `i+1`?

        The reason is mathematical: if you reached stations `i+1`, `i+2`, ..., `j-1` with non-negative fuel (otherwise you would have failed earlier), but still failed at `j`, then starting at any of those intermediate stations means you'd have *less* accumulated fuel when you reach `j`.

        For example, if stations give net gains of `[+3, -1, -1, -2]` and you fail at index 3 starting from index 0, starting at index 1 means you miss the +3 from station 0, making failure even more certain.
      wrong_approach: "Increment start by 1 when failing"
      correct_approach: "Jump start to failure_point + 1"

    - title: Forgetting to Check Total Feasibility
      description: |
        Just finding a valid `start_station` candidate isn't enough. You must verify that the **total gas >= total cost** for the entire circuit.

        The `total_tank` variable serves this purpose. Even if we find a candidate, if `total_tank < 0` at the end, no solution exists.
      wrong_approach: "Only tracking current_tank"
      correct_approach: "Track both current_tank and total_tank"

  key_takeaways:
    - "**Greedy elimination**: When a candidate fails, use problem structure to eliminate multiple candidates at once, not just one"
    - "**Global vs local tracking**: Use separate variables for local decisions (`current_tank`) and global feasibility (`total_tank`)"
    - "**Circular problems**: Often can be solved with a single linear pass by tracking cumulative state"
    - "**Proof intuition**: If total resources >= total cost, a valid starting point must exist — this is a key insight for many resource allocation problems"

  time_complexity: "O(n). We traverse both arrays exactly once, performing constant-time operations at each station."
  space_complexity: "O(1). We only use three integer variables (`total_tank`, `current_tank`, `start_station`) regardless of input size."

solutions:
  - approach_name: Single Pass Greedy
    is_optimal: true
    code: |
      def can_complete_circuit(gas: list[int], cost: list[int]) -> int:
          # Track total surplus to check if solution exists
          total_tank = 0
          # Track current surplus from candidate start
          current_tank = 0
          # Our candidate starting station
          start_station = 0

          for i in range(len(gas)):
              # Net gain/loss at this station
              net = gas[i] - cost[i]
              total_tank += net
              current_tank += net

              # If we can't reach the next station from current start
              if current_tank < 0:
                  # All stations from start to i are invalid
                  # Try starting from the next station
                  start_station = i + 1
                  current_tank = 0

          # If total gas >= total cost, solution exists at start_station
          # Otherwise, impossible to complete the circuit
          return start_station if total_tank >= 0 else -1
    explanation: |
      **Time Complexity:** O(n) — Single pass through both arrays.

      **Space Complexity:** O(1) — Only three integer variables used.

      The key insight is that if we fail to reach station `j` from station `i`, all stations between `i` and `j` are also invalid starting points. Combined with tracking total feasibility, this gives us an elegant linear solution.

  - approach_name: Brute Force
    is_optimal: false
    code: |
      def can_complete_circuit(gas: list[int], cost: list[int]) -> int:
          n = len(gas)

          # Try each station as a starting point
          for start in range(n):
              tank = 0
              can_complete = True

              # Simulate travelling around the circuit
              for i in range(n):
                  # Current station index (wrapping around)
                  station = (start + i) % n
                  # Fill up and travel to next station
                  tank += gas[station] - cost[station]

                  # Ran out of gas before reaching next station
                  if tank < 0:
                      can_complete = False
                      break

              if can_complete:
                  return start

          return -1
    explanation: |
      **Time Complexity:** O(n^2) — For each of n starting points, we simulate travelling n stations.

      **Space Complexity:** O(1) — Only tracking tank and loop variables.

      This approach is correct but inefficient. It tries every possible starting station and simulates the full circuit. With n up to 10^5, this will cause TLE. Included to illustrate why the greedy optimisation is necessary.
