A car travels from a starting position to a destination which is target
miles east of the starting position.
There are gas stations along the way. The gas stations are represented as an array stations
where stations[i] = [position<sub>i</sub>, fuel<sub>i</sub>]
indicates that the i<sup>th</sup>
gas station is position<sub>i</sub>
miles east of the starting position and has fuel<sub>i</sub>
liters of gas.
The car starts with an infinite tank of gas, which initially has startFuel
liters of fuel in it. It uses one liter of gas per one mile that it drives. When the car reaches a gas station, it may stop and refuel, transferring all the gas from the station into the car.
Return the minimum number of refueling stops the car must make in order to reach its destination. If it cannot reach the destination, return -1
.
Note that if the car reaches a gas station with 0
fuel left, the car can still refuel there. If the car reaches the destination with 0
fuel left, it is still considered to have arrived.
Example 1:
target = 1, startFuel = 1, stations = []
Output: 0
(We can reach the target without refueling.)
Example 2:
target = 100, startFuel = 1, stations = [[10,100]]
Output: -1
(We can not reach the target or even the first gas station).
Example 3:
target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]
Output: 2
Explanation: We start with 10 liters of fuel. We drive to position 10, expending 10 liters of fuel. We refuel from 0 liters to 60 liters of gas. Then, we drive from position 10 to position 60 (expending 50 liters of fuel), and refuel from 10 liters to 50 liters of gas. We then drive to and reach the target. We made 2 refueling stops along the way, so we return 2.
One straightforward approach is to use recursion to explore all possible combinations of refueling stops. At each gas station, we have a choice: either stop and refuel or skip it and continue. We recursively explore both options and keep track of the minimum number of stops needed to reach the target.
solve(current_fuel, current_position, index, stops)
:
current_position + current_fuel >= target
, we have reached the target. Return stops
.index >= len(stations)
, we have exhausted all gas stations. Return infinity (float('inf')
) because we cannot reach the target.current_fuel < distance
, return infinity.solve(current_fuel - distance, stations[index][0], index + 1, stops)
.current_fuel < distance
, return infinity.solve(stations[index][1] + current_fuel - distance, stations[index][0], index + 1, stops + 1)
.solve
function with initial fuel, starting position 0, index 0, and 0 stops.```python def min_refuel_stops_recursive(target, startFuel, stations): def solve(current_fuel, current_position, index, stops): if current_position + current_fuel >= target: return stops if index >= len(stations): return float('inf')
# Option 1: Don't stop
distance_to_next = stations[index][0] - current_position
if current_fuel < distance_to_next:
option1 = float('inf')
else:
option1 = solve(current_fuel - distance_to_next, stations[index][0], index + 1, stops)
# Option 2: Stop
if current_fuel < distance_to_next:
option2 = float('inf')
else:
option2 = solve(stations[index][1] + current_fuel - distance_to_next, stations[index][0], index + 1, stops + 1)
return min(option1, option2)
result = solve(startFuel, 0, 0, 0)
return result if result != float('inf') else -1
target = 100 startFuel = 10 stations = [[10, 60], [20, 30], [30, 30], [60, 40]] print(min_refuel_stops_recursive(target, startFuel, stations)) # Output: 2
### Time Complexity
O(2<sup>N</sup>), where N is the number of gas stations. This is because, at each station, we explore two possibilities (stop or don't stop), leading to an exponential number of paths.
### Space Complexity
O(N), due to the depth of the recursion stack.
## Optimal Solution: Dynamic Programming or Greedy Approach
A more efficient approach is to use dynamic programming or a greedy algorithm using a max-heap. The greedy approach is generally preferred due to its efficiency.
### Greedy Algorithm with Max-Heap
The idea is to maintain a max-heap of fuel amounts from the stations we have passed. If we run out of fuel before reaching the next station or the target, we refuel from the station with the most fuel (if available) in the heap.
### Algorithm
1. Initialize a max-heap `heap` (e.g., using Python's `heapq` with negative values to simulate a max-heap).
2. Initialize `current_fuel` with `startFuel` and `stops = 0`.
3. Iterate through the stations:
* Calculate the distance to the next station.
* While `current_fuel < distance`:
* If the heap is empty, it means we cannot reach the next station. Return -1.
* Refuel by adding the largest fuel amount from the heap to `current_fuel`.
* Increment `stops`.
* Subtract the distance from `current_fuel`.
* Add the fuel from the current station to the heap.
4. After iterating through all stations, repeat the refueling process (as in step 3) until we can reach the target.
5. Return the `stops`.
### Code (Python)
```python
import heapq
def min_refuel_stops_greedy(target, startFuel, stations):
heap = [] # Max-heap to store fuel amounts
current_fuel = startFuel
stops = 0
stations.append((target, 0)) # Append target as the last station
last_position = 0
for position, fuel in stations:
distance = position - last_position
while current_fuel < distance:
if not heap:
return -1
current_fuel += -heapq.heappop(heap)
stops += 1
current_fuel -= distance
heapq.heappush(heap, -fuel)
last_position = position
return stops
# Example Usage:
target = 100
startFuel = 10
stations = [[10, 60], [20, 30], [30, 30], [60, 40]]
print(min_refuel_stops_greedy(target, startFuel, stations)) # Output: 2
O(N log N), where N is the number of gas stations. This is because we iterate through each station once, and for each station, we may perform heap operations (push and pop), which take O(log N) time.
O(N), as the max-heap can contain at most all the fuel amounts from the gas stations.
startFuel
is not enough to reach the first gas station, the algorithm should return -1.startFuel
is enough to reach the target directly. If so, return 0; otherwise, return -1.