LeetCode 871 - Minimum Number of Refueling Stops


https://leetcode.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.
Along the way, there are gas stations.  Each station[i] represents a gas station that is station[i][0] miles east of the starting position, and has station[i][1] liters of gas.
The car starts with an infinite tank of gas, which initially has startFuel liters of fuel in it.  It uses 1 liter of gas per 1 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.
What is the least 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't 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.

Note:
  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
X. PQ
https://leetcode.com/problems/minimum-number-of-refueling-stops/discuss/149867/Simple-Java-using-pq-with-explanation
public int minRefuelStops(int target, int startFuel, int[][] stations) {
    int curFarthest = startFuel, refuel = 0;
    PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
    for (int[] station : stations) {
        // check if we can reach this station
        // if we cannot reach this station, refuel the gas from the previous station with most gas
        // redo the operation until we get enough gas to reach this station
        while (curFarthest < station[0]) {
            if (pq.isEmpty()) return -1; // if we reful in each station but still cannot reach this station, return -1
            curFarthest += pq.poll();
            refuel++;
        }
        pq.offer(station[1]);
    }
    // now we have reached the last station, check if we can reach the target
    while (curFarthest < target) {
        if (pq.isEmpty()) return -1;
        curFarthest += pq.poll();
        refuel++;
    }
    return refuel;
}
http://bookshadow.com/weblog/2018/07/15/leetcode-minimum-number-of-refueling-stops/
public int minRefuelStops(int target, int startFuel, int[][] stations) { PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder()); int loc = 0, stop = 0, fuel = startFuel; for (int[] st : stations) { if (fuel + loc >= target) { return stop; } int sloc = st[0], sfuel = st[1]; while (!pq.isEmpty() && fuel < sloc - loc) { fuel += pq.poll(); stop += 1; } if (fuel < sloc - loc) { return -1; } fuel -= sloc - loc; pq.add(sfuel); loc = sloc; } while (!pq.isEmpty() && fuel < target - loc) { fuel += -pq.poll(); stop += 1; } return fuel < target - loc ? -1 : stop; }
https://leetcode.com/problems/minimum-number-of-refueling-stops/discuss/149839/DP-O(N2)-and-Priority-Queue-O(NlogN)
Approach 2: Priority Queue, O(NlogN)
i is the index of next stops to refuel.
res is the times that we have refeuled.
pq is a priority queue that we store all available gas.
We initial res = 0 and in every loop:


  1. We add all reachable stop to priority queue.
  2. We pop out the largest gas from pq and refeul once.
  3. If we can't refuel, means that we can not go forward and return -1


    public int minRefuelStops(int target, int cur, int[][] s) {
        Queue<Integer> pq = new PriorityQueue<>();
        int i = 0, res;
        for (res = 0; cur < target; res++) {
            while (i < s.length && s[i][0] <= cur)
                pq.offer(-s[i++][1]);
            if (pq.isEmpty()) return -1;
            cur += -pq.poll();
        }
        return res;
    }
https://leetcode.com/articles/minimum-number-of-refueling-stops/
 When driving past a gas station, let's remember the amount of fuel it contained. We don't need to decide yet whether to fuel up here or not - for example, there could be a bigger gas station up ahead that we would rather refuel at.
When we run out of fuel before reaching the next station, we'll retroactively fuel up: greedily choosing the largest gas stations first.
This is guaranteed to succeed because we drive the largest distance possible before each refueling stop, and therefore have the largest choice of gas stations to (retroactively) stop at.

pq ("priority queue") will be a max-heap of the capacity of each gas station we've driven by. We'll also keep track of tank, our current fuel.
When we reach a station but have negative fuel (ie. we needed to have refueled at some point in the past), we will add the capacities of the largest gas stations we've driven by until the fuel is non-negative.
If at any point this process fails (that is, no more gas stations), then the task is impossible.

  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;

  }

X. DP
https://blog.csdn.net/XX_123_1_RJ/article/details/81206386
这个题目使用动态规划的思想,基本思路,设dp[i]表示第i次加油之后可以达到的最远距离,很显然,i <= 加油站的个数,求出dp之后,从头遍历一边,找到第一个 dp[i] >= target 的 i ,就是最少的加油次数,如果没有就返回-1。
(1)问题 dp[i] 怎么求? 首先,从头开遍历加油站,每当遍历到第i个加油站时,dp[t+1] = max(dp[t+1], dp[t] + arr[i]),其中t+1 <= i,然后依次,从后向前更新dp,可以这样理解,dp[t] 再加一次油arr[i],得到的新的dp[t+1]是否是比之前的dp[t+1]大?如果大就更新。依次遍历递推,直至结束。值得思考是的,仔细观察递推公式:dp[t+1] = max(dp[t+1], dp[t] + arr[i])你会发现,无论更新与否,dp[t+1] 始终代表的是第 t+1 次加油。
https://leetcode.com/articles/minimum-number-of-refueling-stops/
Time Complexity: O(N^2), where N is the length of stations.
Let's determine dp[i], the farthest location we can get to using i refueling stops. This is motivated by the fact that we want the smallest i for which dp[i] >= target.
Algorithm
Let's update dp as we consider each station in order. With no stations, clearly we can get a maximum distance of startFuel with 0 refueling stops.
Now let's look at the update step. When adding a station station[i] = (location, capacity), any time we could reach this station with t refueling stops, we can now reach capacity further with t+1refueling stops.
For example, if we could reach a distance of 15 with 1 refueling stop, and now we added a station at location 10 with 30 liters of fuel, then we could potentially reach a distance of 45 with 2 refueling stops.

  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;
  }
https://leetcode.com/problems/minimum-number-of-refueling-stops/discuss/151850/C%2B%2B-DP-solution-Space-complexity-from-O(n2)-to-O(n).
Denote by dp[i][j] the farthest location we can get to using exactly j refueling stops among the first i refueling stops, for j <= i.
Initially dp[i][0] = startFuel, for i = 0, ..., n.
dp[][] is updated as follows. For the gas station i, one can either refuel the car at this station if dp[i-1][j-1] >= stations[i][0], and dp[i][j] = max(dp[i][j], dp[i-1][j-1] + stations[i][1]). Or one can choose to not refuel the car, and dp[i][j] = max(dp[i][j], dp[i-1][j]) if j <= i-1.
Here is the code for O(n^2) space complexity dynamic programming.
for (int i = 0; i <= n; i++) dp[i][0] = startFuel;

for (int i = 0; i < n; i++)
 for (int j = 0; j <= i; j++) {
  if (i >= j+1)
   dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j+1]);
  if (dp[i][j] >= stations[i][0])
   dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j] + stations[i][1]);
 }
It is worth pointing out that the (i+1)-th raws depends only on the values on the i-th raws. Hence, we can reduce the space complexity.
The previous code is equivalent to
dp[0] = startFuel;
for (int i = 0; i < n; i++)
 for (int j = i; j >= 0; j--) {
  if (dp[j] >= stations[i][0])
   dp[j+1] = max(dp[j+1], dp[j] + stations[i][1]);
 }
https://leetcode.com/problems/minimum-number-of-refueling-stops/discuss/149839/DP-O(N2)-and-Priority-Queue-O(NlogN)
dp[t] means the furthest distance that we can get with t times of refueling.
So for every station s[i],
if the current distance dp[t] >= s[i][0], we can refuel:
dp[t + 1] = max(dp[t + 1], dp[t] + s[i][1])


In the end, we'll return the first t with dp[i] >= target,
otherwise we'll return -1.


    public int minRefuelStops(int target, int startFuel, int[][] s) {
        long[] dp = new long[s.length + 1];
        dp[0] = startFuel;
        for (int i = 0; i < s.length; ++i)
            for (int t = i; t >= 0 && dp[t] >= s[i][0]; --t)
                dp[t + 1] = Math.max(dp[t + 1], dp[t] + s[i][1]);
        for (int t = 0; t <= s.length; ++t)
            if (dp[t] >= target) return t;
        return -1;
    }


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts