2021-03-13

[Leetcode]1326.灌溉花园的最少水龙头数目

这道题是45.跳跃游戏的进阶版,和跳跃游戏的不同在于,这道题的背景稍微复杂,一个点可以往左右两边浇水,我们需要把这个转换成跳跃游戏。如何转换呢?
可以这样想,把每个点可以浇的水的范围[l, r],就当成是一个人在 l 点最远可以跳到r点,或者看成一个人在r点最远可以跳到l点。因为跳跃游戏规定了是向后跳,所以跳跃游戏只需要单向考虑就行。
这道题的话,不管是从左边按照跳跃游戏的方式遍历到右边,还是从右边遍历到左边都可以。
这道题还有一个注意点,就是一开始需要预处理出跳跃游戏的那个数组,官方解答给的是对于一个右端点,预处理prev数组,其实就是从后往前跳的跳跃游戏。这道题不容易理解的就是,跳跃游戏每个点,假如不是0的话,都可以是一段区间的最左边界,属于稠密区间,而本题可能会不能全部浇完,属于稀疏区间,不是每个prev[i]都是有意义的,如果prev[i] == i的话,说明是有区间的缺失,等于跳跃游戏中,nums[i] == 0,这里稍微难理解一些。

  • 贪心法
	public int minTaps(int n, int[] ranges) {
        int[] prev = new int[n + 1];
        for(int i = 0; i < n + 1; i++){
            prev[i] = i;
        } 
        for (int i = 0; i <= n; ++i) {
            int l = Math.max(i - ranges[i], 0);
            int r = Math.min(i + ranges[i], n);
            prev[r] = Math.min(prev[r], l);
        }
        //上面其实做的就是初始化跳跃游戏的nums数组
        int step = 0;
        int min = n;
        int onestep_maxrange = n;
        for(int i = n; i > 0; i--){
            min = Math.min(min, prev[i]);
            if(i == onestep_maxrange){
                if(min >= onestep_maxrange){
                    return -1;
                }
                onesteprange = min;
                step++;
            }
        }
        
        return step;
    }
  • 动态规划
	public int minTaps(int n, int[] ranges) {
        int[] dp = new int[n + 1];
        Arrays.fill(dp, (int)2e9);
        dp[n] = 0;
        int[] prev = new int[n + 1];
        for(int i = 0; i < n + 1; i++){
            prev[i] = i;
        }
        for(int i = 0; i <= n; i++){
            int l = Math.max(0, i - ranges[i]);
            int r = Math.min(n, i + ranges[i]);
            prev[r] = Math.min(l, prev[r]);
        }
        // System.out.println(Arrays.toString(prev));
        for(int i = n; i >= 0; i--){
            for(int j = prev[i]; j < i; j++){
                dp[j] = Math.min(dp[j], dp[i] + 1);
            }
        }
        return dp[0] == (int)2e9 ? -1 : dp[0];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值