加载中...
871-最低加油次数(Minimum Number of Refueling Stops)
发表于:2021-12-03 | 分类: 困难
字数统计: 1.7k | 阅读时长: 7分钟 | 阅读量:

原文链接: https://leetcode-cn.com/problems/minimum-number-of-refueling-stops

英文原文

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] = [positioni, fueli] indicates that the ith gas station is positioni miles east of the starting position and has fueli 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 <= 109
  • 0 <= stations.length <= 500
  • 0 <= positioni <= positioni+1 < target
  • 1 <= fueli < 109

中文题目

汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。

沿途有加油站,每个 station[i] 代表一个加油站,它位于出发位置东面 station[i][0] 英里处,并且有 station[i][1] 升汽油。

假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 1 英里就会用掉 1 升汽油。

当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。

为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 -1

注意:如果汽车到达加油站时剩余燃料为 0,它仍然可以在那里加油。如果汽车到达目的地时剩余燃料为 0,仍然认为它已经到达目的地。

 

示例 1:

输入:target = 1, startFuel = 1, stations = []
输出:0
解释:我们可以在不加油的情况下到达目的地。

示例 2:

输入:target = 100, startFuel = 1, stations = [[10,100]]
输出:-1
解释:我们无法抵达目的地,甚至无法到达第一个加油站。

示例 3:

输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]
输出:2
解释:
我们出发时有 10 升燃料。
我们开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。
然后,我们从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料),
并将汽油从 10 升加到 50 升。然后我们开车抵达目的地。
我们沿途在1两个加油站停靠,所以返回 2 。

 

提示:

  1. 1 <= target, startFuel, stations[i][1] <= 10^9
  2. 0 <= stations.length <= 500
  3. 0 < stations[0][0] < stations[1][0] < ... < stations[stations.length-1][0] < target

通过代码

官方题解

方法一: 动态规划

思路

dp[i] 为加 i 次油能走的最远距离,需要满足 dp[i] >= target 的最小 i

算法

依次计算每个 dp[i],对于 dp[0],就只用初始的油量 startFuel 看能走多远。

每多一个加油站 station[i] = (location, capacity),如果之前可以通过加 t 次油到达这个加油站,现在就可以加 t+1 次油得到 capcity 的油量。

举个例子,原本加一次油可以行驶的最远距离为 15,现在位置 10 有一个加油站,有 30 升油量储备,那么显然现在可以加两次油行驶 45 距离。

[solution1-Java]
class Solution { public int minRefuelStops(int target, int startFuel, int[][] stations) { int N = stations.length; long[] dp = new long[N + 1]; dp[0] = startFuel; for (int i = 0; i < N; ++i) for (int t = i; t >= 0; --t) if (dp[t] >= stations[i][0]) dp[t+1] = Math.max(dp[t+1], dp[t] + (long) stations[i][1]); for (int i = 0; i <= N; ++i) if (dp[i] >= target) return i; return -1; } }
[solution1-Python]
class Solution(object): def minRefuelStops(self, target, startFuel, stations): dp = [startFuel] + [0] * len(stations) for i, (location, capacity) in enumerate(stations): for t in xrange(i, -1, -1): if dp[t] >= location: dp[t+1] = max(dp[t+1], dp[t] + capacity) for i, d in enumerate(dp): if d >= target: return i return -1

复杂度分析

  • 时间复杂度: $O(N^2)$,其中 $N$ 为加油站的个数。

  • 空间复杂度: $O(N)$,dp 数组占用的空间。

方法二:栈

思路

每驶过一个加油站,记住这个加油站有多少油。不需要立即决定要不要在这个加油站加油,如果后面有油量更多的加油站显然优先选择后面的加油。

如果当前油量不够抵达下一个加油站,必须得从之前的加油站中找一个来加油,贪心选择最大油量储备的加油站就好了。

算法

定义 pq(优先队列)为一个保存了驶过加油站油量的最大堆,定义当前油量为 tank

如果当前油量为负数(意味着当前油量不够抵达当前位置),那就必须在驶过的加油站找一个油量储备最大来加油。

如果在某个位置油量为负,且没有加油站可用了,那就不可能完成这个任务。

[solution2-Java]
class Solution { public int minRefuelStops(int target, int tank, int[][] stations) { // pq is a maxheap of gas station capacities PriorityQueue<Integer> pq = new PriorityQueue(Collections.reverseOrder()); int ans = 0, prev = 0; for (int[] station: stations) { int location = station[0]; int capacity = station[1]; tank -= location - prev; while (!pq.isEmpty() && tank < 0) { // must refuel in past tank += pq.poll(); ans++; } if (tank < 0) return -1; pq.offer(capacity); prev = location; } // Repeat body for station = (target, inf) { tank -= target - prev; while (!pq.isEmpty() && tank < 0) { tank += pq.poll(); ans++; } if (tank < 0) return -1; } return ans; } }
[solution2-Python]
class Solution(object): def minRefuelStops(self, target, tank, stations): pq = [] # A maxheap is simulated using negative values stations.append((target, float('inf'))) ans = prev = 0 for location, capacity in stations: tank -= location - prev while pq and tank < 0: # must refuel in past tank += -heapq.heappop(pq) ans += 1 if tank < 0: return -1 heapq.heappush(pq, -capacity) prev = location return ans

复杂度分析

  • 时间复杂度: $O(N \log N)$,其中 $N$ 为加油站的个数。

  • 空间复杂度: $O(N)$, pq 数组占用的空间。

统计信息

通过次数 提交次数 AC比率
10267 29734 34.5%

提交历史

提交时间 提交结果 执行时间 内存消耗 语言
上一篇:
868-二进制间距(Binary Gap)
下一篇:
870-优势洗牌(Advantage Shuffle)
本文目录
本文目录