# 134. Gas Station

LeetCode Problem Link (opens new window)

There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

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

Return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1.

Note:

  • The solution is guaranteed to be unique if it exists.
  • Both input arrays are non-empty and have the same length.
  • Each element in the input arrays is a non-negative integer.

Example 1:
Input:

  • gas = [1,2,3,4,5]
  • cost = [3,4,5,1,2]

Output: 3
Explanation:

  • Start at station 3, with 4 of gas, then your tank has 0 + 4 = 4 of gas
  • Travel to station 4, your tank has 4 - 1 + 5 = 8 of gas
  • Travel to station 0, your tank has 8 - 2 + 1 = 7 of gas
  • Travel to station 1, your tank has 7 - 3 + 2 = 6 of gas
  • Travel to station 2, your tank has 6 - 4 + 3 = 5 of gas
  • Travel to station 3, you must consume 5 of gas, which is exactly enough to return to station 3.
  • Therefore, 3 is the starting index.

Example 2:
Input:

  • gas = [2,3,4]
  • cost = [3,4,3]

Output: -1
Explanation: You cannot start at station 0 or 1 as you do not have enough gas to reach the next station. Starting at station 2, you get 4 gas, and your tank has 0 + 4 = 4 gas.
Travel to station 0, your tank has 4 - 3 + 2 = 3 gas.
Travel to station 1, your tank has 3 - 3 + 3 = 3 gas.
You cannot return to station 2 since you'll need 4 of gas, but your tank only has 3.
Thus, it is impossible to travel the circuit in one go no matter how you start.

# Thoughts

# Brute Force Method

The brute force solution is obviously O(n^2), where we try starting from each gas station and simulate the journey around the circuit.

If after completing the loop, if we have not run out of gas midway, and the final gas in the tank is more than or equal to 0, this starting point is valid.

The brute force method requires simulating the loop, and is not easy to code. The key is simulating the entire circuit.

The for loop is suitable for a linear pass, while the while loop is suitable for a circular traverse, utilize while wisely!

Here's the C++ code:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        for (int i = 0; i < cost.size(); i++) {
            int rest = gas[i] - cost[i]; // Track remaining gas
            int index = (i + 1) % cost.size();
            while (rest > 0 && index != i) { // Simulate starting at i for one lap (if rest==0, the solution is not unique)
                rest += gas[index] - cost[index];
                index = (index + 1) % cost.size();
            }
            // If starting at i for one lap, gas remaining >=0, return the starting position
            if (rest >= 0 && index == i) return i;
        }
        return -1;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  • Time Complexity: O(n^2)
  • Space Complexity: O(1)

# Greedy Algorithm (Method One)

Let's perform greedy selection globally in the following scenarios:

  • Case One: If the total gas is less than the total cost, then it's impossible to complete one circuit regardless of where you start.
  • Case Two: Track the remaining gas rest[i] = gas[i]-cost[i], accumulate it from the start to the last station. If there is a point where the cumulative sum never drops below zero, point zero can be the starting point.
  • Case Three: If the cumulative minimum value is negative, start from a non-zero point, looking backward to find any station that can offset this negative value, and it will be the starting point.

Here's the C++ code:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int min = INT_MAX; // Track the smallest gas level in the tank from the start
        for (int i = 0; i < gas.size(); i++) {
            int rest = gas[i] - cost[i];
            curSum += rest;
            if (curSum < min) {
                min = curSum;
            }
        }
        if (curSum < 0) return -1;  // Case 1
        if (min >= 0) return 0;     // Case 2
                                    // Case 3
        for (int i = gas.size() - 1; i >= 0; i--) {
            int rest = gas[i] - cost[i];
            min += rest;
            if (min >= 0) {
                return i;
            }
        }
        return -1;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  • Time Complexity: O(n)
  • Space Complexity: O(1)

In my opinion, this is not exactly a greedy algorithm since it doesn't really find a locally optimal solution but rather considers the global optimum directly, though the approach is clever.

Despite this, we call this a greedy algorithm because the solution was derived directly from global optimization. This method is still clever and demonstrates a unique perspective, worth considering.

# Greedy Algorithm (Method Two)

Consider another approach: If the total gas minus the total cost is greater than or equal to zero, it is possible to complete a full loop, and the overall remaining gas rest[i] sum is non-negative.

Every gas station's surplus rest[i] is gas[i] - cost[i].

Starting from i=0, accumulate rest[i], with the sum recorded as curSum. As soon as curSum is less than zero, none of [0, i] can be the starting point, because this segment will always run out of gas at i, meaning the starting point must begin after i. Then reset curSum to zero.

Illustration:

Why is a start point valid if sum from [0 to i] <0 can be simply set to i+1 forward, as curSum will never go lower than it? If it did, more nodes, aka i, would be reset thus repositioning the starting point to i+1 again.

Is it possible for a point in [0, i] to keep curSum non-negative? Higher partition of [0, i] into sections 1, 2, etc. ensuring each section, for example section 2, keeps curSum >=0.

With local optimization: current cumulated rest[i] sum curSum as soon less than 0 signifies start point at least i+1 as starting [0 to i-1] inevitably ran out fuel as per illustration. Global optimization: Find starting point travelling one full circuit.

Local optimum can promote global optimum, let's challenge this with Greedy!

Here's the C++ code:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int curSum = 0;
        int totalSum = 0;
        int start = 0;
        for (int i = 0; i < gas.size(); i++) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if (curSum < 0) {   // As soon as current accumulation rest[i] and curSum < 0
                start = i + 1;  // Starting position is updated to i+1
                curSum = 0;     // curSum starts from 0
            }
        }
        if (totalSum < 0) return -1; // Implies it's impossible to complete a circuit
        return start;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • Time Complexity: O(n)
  • Space Complexity: O(1)

This approach embodies the real greedy algorithm ethos, as the global optimal solution is deduced through local optima, with a clear absence of counter-examples, making it concluded feasible!

# Conclusions

Initially proposing a brute force method, the brute force simulation of a loop is quite challenging requiring adept control over while usage.

Followed by two greedy algorithm approaches, the first of which I believe involves direct global optimal simulation, a clever idea, intriguing too.

The second greedy method showcases the essence of greedy strategy, where local optimum is transitionally leading to global optimum solution for selecting a starting position.

# Others language versions

# Java

// Solution 1
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int sum = 0;
        int min = 0;
        for (int i = 0; i < gas.length; i++) {
            sum += (gas[i] - cost[i]);
            min = Math.min(sum, min);
        }

        if (sum < 0) return -1;
        if (min >= 0) return 0;

        for (int i = gas.length - 1; i > 0; i--) {
            min += (gas[i] - cost[i]);
            if (min >= 0) return i;
        }

        return -1;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Solution 2
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int curSum = 0;
        int totalSum = 0;
        int index = 0;
        for (int i = 0; i < gas.length; i++) {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if (curSum < 0) {
                index = (i + 1) % gas.length ; 
                curSum = 0;
            }
        }
        if (totalSum < 0) return -1;
        return index;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Solution 3
class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int tank = 0; // current fuel
        int totalGas = 0;  // total gas
        int totalCost = 0; // total cost
        int start = 0; // start point
        for (int i = 0; i < gas.length; i++) {
            totalGas += gas[i];
            totalCost += cost[i];
            
            tank += gas[i] - cost[i];
            if (tank < 0) { // tank becomes negative indicates starting from 0 to i cannot make a full circuit due to fuel shortage
                tank = 0; // reset tank, similar to Problem 53
                start = i + 1; // set start point to i+1
            }
        }
        if (totalCost > totalGas) return -1;
        return start;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# Python

Brute force

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        for i in range(len(cost)):
            rest = gas[i] - cost[i]  # Track remaining gas
            index = (i + 1) % len(cost)  # Index of the next gas station

            while rest > 0 and index != i:  # Simulate starting at i around one loop (if rest==0, the answer is not unique)
                rest += gas[index] - cost[index]  # Update the remainding gas
                index = (index + 1) % len(cost)  # Update the index of the next gas station

            if rest >= 0 and index == i:  # If starting at i for one lap, remaining gas >=0, and returns to start position
                return i  # Return starting position i

        return -1  # No starting position can loop once, return -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Greedy (version one)

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        curSum = 0  # Current cumulative remaining fuel
        minFuel = float('inf')  # The smallest amount of fuel in the tank from start
        for i in range(len(gas)):
            rest = gas[i] - cost[i]
            curSum += rest
            if curSum < minFuel:
                minFuel = curSum
        
        if curSum < 0:
            return -1  # Case 1: whole trip's total consumption > total provision, a single loop is impossible
        
        if minFuel >= 0:
            return 0  # Case 2: starting from start, the remaining fuel for all stations does not drop below 0
        
        for i in range(len(gas) - 1, -1, -1):
            rest = gas[i] - cost[i]
            minFuel += rest
            if minFuel >= 0:
                return i  # Case 3: locate station from which starting can ensure fuel is always >=0; return the index
        
        return -1  # Completing a loop isn't possible
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Greedy (version two)

class Solution:
    def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
        curSum = 0  # Current cumulative remainder fuel
        totalSum = 0  # Total remaining fuel
        start = 0  # Starting index

        for i in range(len(gas)):
            curSum += gas[i] - cost[i]
            totalSum += gas[i] - cost[i]

            if curSum < 0:  # Current cumulative rest[i] sums per curSum is negative
                start = i + 1  # Starting index updates to i+1
                curSum = 0  # Reset curSum
            
        if totalSum < 0:
            return -1  # Total remaining fuel totalSum < 0, completing a loop is impossible
        return start
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Go

Greedy Algorithm (Method One)

func canCompleteCircuit(gas []int, cost []int) int {
    curSum := 0
    min := math.MaxInt64
    for i := 0; i < len(gas); i++ {
        rest := gas[i] - cost[i]
        curSum += rest
        if curSum < min {
            min = curSum
        }
    }
    if curSum < 0 {
        return -1
    }
    if min >= 0 {
        return 0
    }
    for i := len(gas) - 1; i > 0; i-- {
        rest := gas[i] - cost[i]
        min += rest
        if min >= 0 {
            return i
        }
    }
    return -1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Greedy Algorithm (Method Two)

func canCompleteCircuit(gas []int, cost []int) int {
	curSum := 0
	totalSum := 0
	start := 0
	for i := 0; i < len(gas); i++ {
		curSum += gas[i] - cost[i]
		totalSum += gas[i] - cost[i]
		if curSum < 0 {
			start = i + 1
			curSum = 0
		}
	}
	if totalSum < 0 {
		return -1
	}
	return start
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# JavaScript

Brute force:

var canCompleteCircuit = function(gas, cost) {
    for(let i = 0; i < cost.length; i++) {
        let rest = gas[i] - cost[i]  // track remaining fuel
        // Walk a full lap starting from i, index is the next station
        let index = (i + 1) % cost.length
        while(rest > 0 && index !== i) {
            rest += gas[index] - cost[index]
            index = (index + 1) % cost.length
        }
        if(rest >= 0 && index === i) return i
    }
    return -1
};
1
2
3
4
5
6
7
8
9
10
11
12
13

Method One:

var canCompleteCircuit = function(gas, cost) {
    let curSum = 0
    let min = Infinity
    for(let i = 0; i < gas.length; i++) {
        let rest = gas[i] - cost[i]
        curSum += rest
        if(curSum < min) {
            min = curSum
        }
    }
    if(curSum < 0) return -1   //1. Total fuel less than total cost
    if(min >= 0) return 0      //2. Indicates fuel didn't break during travel
                               //3. From rear to fore, look for stations able to offset this negative point, and start from there
    for(let i = gas.length -1; i >= 0; i--) {
        let rest = gas[i] - cost[i]
        min += rest
        if(min >= 0) {
            return i
        }
    }
    return -1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Method Two:

var canCompleteCircuit = function(gas, cost) {
    const gasLen = gas.length
    let start = 0
    let curSum = 0
    let totalSum = 0

    for(let i = 0; i < gasLen; i++) {
        curSum += gas[i] - cost[i]
        totalSum += gas[i] - cost[i]
        if(curSum < 0) {
            curSum = 0
            start = i + 1
        }
    }

    if(totalSum < 0) return -1

    return start
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# TypeScript

Brute force:

function canCompleteCircuit(gas: number[], cost: number[]): number {
    for (let i = 0, length = gas.length; i < length; i++) {
        let curSum: number = 0;
        let index: number = i;
        while (curSum >= 0 && index < i + length) {
            let tempIndex: number = index % length;
            curSum += gas[tempIndex] - cost[tempIndex];
            index++;
        }
        if (index === i + length && curSum >= 0) return i;
    }
    return -1;
};
1
2
3
4
5
6
7
8
9
10
11
12
13

Method Two:

function canCompleteCircuit(gas: number[], cost: number[]): number {
    let total: number = 0;
    let curGas: number = 0;
    let tempDiff: number = 0;
    let resIndex: number = 0;
    for (let i = 0, length = gas.length; i < length; i++) {
        tempDiff = gas[i] - cost[i];
        total += tempDiff;
        curGas += tempDiff;
        if (curGas < 0) {
            resIndex = i + 1;
            curGas = 0;
        }
    }
    if (total < 0) return -1;
    return resIndex;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Rust

Greedy Algorithm: Method One

impl Solution {
    pub fn can_complete_circuit(gas: Vec<i32>, cost: Vec<i32>) -> i32 {
        let mut cur_sum = 0;
        let mut min = i32::MAX;
        for i in 0..gas.len() {
            let rest = gas[i] - cost[i];
            cur_sum += rest;
            if cur_sum < min { min = cur_sum; }
        }
        if cur_sum < 0 { return -1; }
        if min > 0 { return 0; }
        for i in (0..gas.len()).rev() {
            let rest = gas[i] - cost[i];
            min += rest;
            if min >= 0 { return i as i32; }
        }
        -1
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Greedy Algorithm: Method Two

impl Solution {
    pub fn can_complete_circuit(gas: Vec<i32>, cost: Vec<i32>) -> i32 {
        let mut cur_sum = 0;
        let mut total_sum = 0;
        let mut start = 0;
        for i in 0..gas.len() {
            cur_sum += gas[i] - cost[i];
            total_sum += gas[i] - cost[i];
            if cur_sum < 0 {
                start = i + 1;
                cur_sum = 0;
            }
        }
        if total_sum < 0 { return -1; }
        start as i32
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# C

Greedy Algorithm: Method One

int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
    int curSum = 0;
    int i;
    int min = INT_MAX;
    // Traverse the entire array. Calculate the remaining fuel difference at each station, and compare it with minimum cumulative amount.
    for(i = 0; i < gasSize; i++) {
        int diff = gas[i] - cost[i];
        curSum += diff;
        if(curSum < min)
            min = curSum;
    }
    // If the total fuel is negative, it's impossible to complete a full circuit. Return -1
    if(curSum < 0)
        return -1;
    // If min is greater than or equal to 0, every trip's fuel is greater than consumption, allowing departure from zero.
    if(min >= 0)
        return 0;
    // If minimum accumulated is negative, find a non-zero element (fuel exceeds cost) to start. Return the index.
    for(i = gasSize - 1; i >= 0; i--) {
        min+=(gas[i]-cost[i]);
        if(min >= 0)
            return i;
    }
    // Won't logically return this 0
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Greedy Algorithm: Method Two

int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
    int curSum = 0;
    int totalSum = 0;
    int start = 0;

    int i;
    for(i = 0; i < gasSize; ++i) {
        // The difference between fuel and consumption at the current i station
        int diff = gas[i] - cost[i];

        curSum += diff;
        totalSum += diff;

        // If the gas from 0 to i is negative, start position should be i+1
        if(curSum < 0) {
            curSum = 0;
            // When i + 1 == gasSize, totalSum < 0 (i at gasSize - 1), the car cannot return to the origin
            start = i + 1;
        }
    }

    // If total is less than 0, the fuel car can never return to the origin. Return -1
    if(totalSum < 0)
        return -1;

    return start;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# Scala

Brute Force:

object Solution {
  def canCompleteCircuit(gas: Array[Int], cost: Array[Int]): Int = {
    for (i <- cost.indices) {
      var rest = gas(i) - cost(i)
      var index = (i + 1) % cost.length // index is the next node of i
      while (rest > 0 && i != index) {
        rest += (gas(index) - cost(index))
        index = (index + 1) % cost.length
      }
      if (rest >= 0 && index == i) return i
    }
    -1
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Greedy Algorithm: Method One

object Solution {
  def canCompleteCircuit(gas: Array[Int], cost: Array[Int]): Int = {
    var curSum = 0
    var min = Int.MaxValue
    for (i <- gas.indices) {
      var rest = gas(i) - cost(i)
      curSum += rest
      min = math.min(min, curSum)
    }
    if (curSum < 0) return -1 // Case 1: total gas is less than total cost, cannot reach destination
    if (min >= 0) return 0 // Case 2: min >= 0, can start from 0 and reach
    // Case 3: if min is negative, search backwards for a station that fills the minimum
    for (i <- gas.length - 1 to 0 by -1) {
      var rest = gas(i) - cost(i)
      min += rest
      if (min >= 0) return i
    }
    -1
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Greedy Algorithm: Method Two

object Solution {
  def canCompleteCircuit(gas: Array[Int], cost: Array[Int]): Int = {
    var curSum = 0
    var totalSum = 0
    var start = 0
    for (i <- gas.indices) {
      curSum += (gas(i) - cost(i))
      totalSum += (gas(i) - cost(i))
      if (curSum < 0) {
        start = i + 1 // Update starting point
        curSum = 0  // Reset curSum
      }
    }
    if (totalSum < 0) return -1 // Impossible to go full circle
    start
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# C#

// Greedy Algorithm, Version Two
public class Solution
{
    public int CanCompleteCircuit(int[] gas, int[] cost)
    {
        int curSum = 0, totalSum = 0, start = 0;
        for (int i = 0; i < gas.Length; i++)
        {
            curSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if (curSum < 0)
            {
                start = i + 1;
                curSum = 0;
            }
        }
        if (totalSum < 0) return -1;
        return start;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Last updated:: 9/4/2025, 3:19:38 PM
Copyright © 2025 keetcoder