Minimum Number of Refueling Stops

Question:

请添加图片描述

思路:

这个题两个方法:
1.dp 2.heap

  1. dp方法我们可以设置mem table.mem[i]. 然后 mem[i] 代表请添加图片描述

用I个refuel最远可以走多远.
然后最后结尾的时候只要loop mem[i] 找到最早先大于target 就行.
然后这个dp approach在循环中, 每次我们都是先从小的开始.

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]);

这个其实就是主要循环的code. update mem table的.
我们按照顺序一个一个处理station.
我们会先判断当前走的最远距离能不能走到第i个station. 如果可以走到, 那我们就更新dp[i+1], 其实dp[i+1] 就是用第i+1个station refuel可以走多远, 为什么是i+1呢, 首先我们的station 0 其实就是一个station. 按理说dp[0] 应该是用station0可以最远走多远, 但是这和我们定义的dp table 实际表达意思不符,dp[0]应该代表不refuel 最远可以走多远, 就是startFuel. 那么, 这里第i个station. 就其实是dp[i+1]这里的使用. 然后dp[i+1] = max(dp[i] + station[1], 这个好理解,直接加上前一个, dp[i+1]) 为什么这里还有个dp[i+1]呢, 难道不是这个永远都没有前面那个大吗?
不是这样的, 每次我们先碰到一个station, dp[i+1]确实=0, 但是我们的inner loop是从i 往 0 循环, 所以. 到后面的loop的时候, 我们会重新判断以前的选择. 就是相当于, 我们又多了一个station 可以在i个refuel 之内 refuel, 就是说我们要判断, 如果我i个stop refuel里可不可以把当前这个加油站考虑进去, 然后如果我考虑进去的话, 那我之前那些加油站我少加一次,换成加这个station, 会不会比我原先加的那些station 总公里数更远.
举个例子就像 我startFuel = 30, 然后station = [[10,10],[20,50]], dp[] = [30,0,0]
在我第二次run loop的时候. dp[1] >= station[1][0]
然后更新dp[2]
接着回到dp[0] = 30 >= station[1][0] = 20
然后再更新一次dp[1], 找一下 refuel 1次可以行驶的最远距离.
这里就相当于, 我们在判断, 我的startFuel是不是也可以直接加station1. 而且我直接加station1 不加 station0 是不是可以走的更远. 这个时候dp[1] = max(dp[1] 这里就是原先用station[0]的值, 和dp[0] + …) 就能理解了
所以dp[] 里存的就是refuel i 次, 可以走的最远距离

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]);
                else break;
        for (int i = 0; i <= N; ++i)
            if (dp[i] >= target) return i;
        return -1;
    }
}

用heap
这个就有点儿偏greedy了. 就是我们想要行驶的最远加油最少, 肯定是我们不到万不得已不加油, 而且要加也得每次加油最多的station. 那首先要想加油, 我们得先能行驶到station才行. 那我们就可以先往target 走, 然后用一个max heap存每个加油站的油. 走到我们没有用必须得加的时候, 我们每次都先加先前经过的油最多的station. 直到我们走到没油,而且经过的station油都加了.还是到不了下一个加油站或者target,那就代表到不了.

class Solution {
    public int minRefuelStops(int target, int startFuel, int[][] stations) {
        PriorityQueue<Integer> max = new PriorityQueue<>((a,b)->b-a);
        int res = 0;
        int prevStation = 0;
        for(int[] station: stations){
            // each time we reduce a station distance, we are actually repeatly reduce a previous sattion distance also, so we need to add it back
            startFuel -= (station[0] - prevStation);
            while(!max.isEmpty() && startFuel < 0){
                startFuel += max.poll();
                res++;
            }
            if(startFuel < 0) return -1;
            max.add(station[1]);
            prevStation = station[0];
        }
        
        // in the last step, still need to check if we can made to target.
        startFuel -= (target - prevStation);
        while(!max.isEmpty() && startFuel < 0){
                startFuel += max.poll();
                res++;
        }
        if(startFuel < 0) return -1;
        
        return res;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值