KK's blog

每天积累多一些

0%

LeetCode 871 Minimum Number of Refueling Stops

LeetCode



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:

Input: target = 1, startFuel = 1, stations = []
Output: 0
Explanation: We can reach the target without refueling.


Example 2:

Input: target = 100, startFuel = 1, stations = [[10,100]]
Output: -1
Explanation: We can not reach the target (or even the first gas station).


Example 3:

Input: 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.


Constraints:

1 <= target, startFuel <= 10<sup>9</sup> 0 <= stations.length <= 500
0 <= position<sub>i</sub> <= position<sub>i+1</sub> < target 1 <= fuel<sub>i</sub> < 10<sup>9</sup>

题目大意:

其最小加油次数使得能到达目标

Heap解题思路(推荐):

由于是重叠区间题且贪婪法加找最大油加油站,考虑用heap。求最小值,所以用最大堆。heap存的油数。

注意事项:

  1. 每到一个加油站,先将油预存到heap中。startFuel为到达某个站后的剩余油数,若startFuel为负,从heap中取油,且累计加油次数。
  2. 用heap模板,遍历数组也就是加油站。
  3. 若加完油后,仍为负数,返回-1。
  4. 因为要计算target是否能达到,所以不妨将target加入到stations中,这样startFuel的计算可以包括target

Python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
def minRefuelStops(self, target: int, startFuel: int, stations: List[List[int]]) -> int:
heap, res, prev_pos = [], 0, 0
stations.append([target, 0])
for pos, fuel in stations:
startFuel -= pos - prev_pos
while heap and startFuel < 0:
startFuel += -heapq.heappop(heap)
res += 1
if startFuel < 0:
return -1
heapq.heappush(heap, -fuel)
prev_pos = pos
return res

算法分析:

时间复杂度为O(nlogn),空间复杂度O(n)


DP算法II解题思路:

一开始考虑用jump game,但此题可以在同一层加多次油。比如start fuel有100 mi,而加油站有3个,所以同一层可以加3次油。所以层数和加油次数不是一个概念。
既然是最值考虑另一种方法DP。这题有两个难点:
第一个难点是DP式: dp不采用题目的最小加油次数,考虑jump game的分析,转化成dp[i]为停i个站加油能达到的最远距离。或者这样思考,若定义走到第n个站需要最小加油次数,这个n颗粒度不够细,可以换成miles,不如将下标和数值互换。
第二个难点是递归式。首先知道假设dp[2]能到达的范围内有一个加油站,加油后dp[3] = dp[2] + 该油站的油数。递归式为:

1
dp[i] = max{dp[i-1] + stations[i-1][1]}, dp[i-1] >= stations[i-1][0], stations[i..n]

有个前提条件是dp[2]必须能达到当前的加油站。比如要更新dp[3]从任意两个加油站dp[2] + 加油站[i]可能获得。还可能是从dp[2] + 加油站[i+1]获得,如此类推,要试完stations[i..n]。
dp值从后往前更新,因为当前加油站在后方。

解题步骤:

N/A

注意事项:

  1. dp定义和递归式

Python代码:

1
2
3
4
5
6
7
8
9
10
11
12
# dp[i] = max{dp[i-1] + stations[i-1][1]}, dp[i-1] >= stations[i-1][0], stations[i..n]
def minRefuelStops(self, target: int, startFuel: int, stations: List[List[int]]) -> int:
dp = [startFuel] + [0] * len(stations)
for i, (pos, fuel) in enumerate(stations):
for j in range(i, -1, -1):
if dp[j] >= pos:
dp[j + 1] = max(dp[j + 1], dp[j] + fuel)

for i, miles in enumerate(dp):
if miles >= target:
return i
return -1

算法分析:

时间复杂度为O(n2),空间复杂度O(n)

Free mock interview