84、★贪心、动态规划-LeetCode.45跳跃游戏Ⅱ-华为笔试

题目描述

给你一个非负整数数组 nums ,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

假设你总是可以到达数组的最后一个位置。

来源:力扣(LeetCode)

思路:贪心难想,想到的动态规划时间复杂度高!

1)动态规划:记录到达每个位置的最短跳数;每个位置的计算,返回从头,去查找可以跳到该位置的位置,记录其dp[j] + 1,每次取出最小的!

一个优化:

每次记录之前范围内最优的情况!

从左起,最先找到的能到达的,一定是最优情况?

确实:每个位置都是最优的到达步数,后面一位,要么和前面一样,要么要加1!前面一定是最小的!下次只用从新位置开始查找即可!

        int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
        int start = 0;
        for(int i = 1;i < nums.length;i++){
            for(int j = start;j < i;j++){
                if(nums[j] + j >= i){
                    dp[i] = dp[j] + 1;
                    start = j;
                    break;
                }
            }
        }
        return dp[nums.length - 1];

2)贪心:①    //从后往前,每次找最大?

每次都尽可能走最大的,也就是找到下一步可到达的最大位置下标!

将end作为step加不加1的标准!

每走一步,要更新一下活动的范围区间!

将最后走的位置,放在倒数第二个元素位置,判断需不需要再走最后一步!

其实也就是边界的处理

如果nums长度为1,进不去for;如果长度大于1,进去数组还要走一步!

代码

1)把自己整笑的动态规划:时间复杂度 n^2,甚至还要大

class Solution {
    public int jump(int[] nums) {
        int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
        dp[0] = 0;
        for(int i = 1;i < nums.length;i++){
            dp[i] = Integer.MAX_VALUE;
            for(int j = 0;j < i;j++){
                if(nums[j] + j >= i){
                    dp[i] = Math.min(dp[i],dp[j] + 1);
                }
            }
        }
        return dp[nums.length - 1];
    }
}

2)动态规划优化,需要理解

class Solution {
    public int jump(int[] nums) {
        int[] dp = new int[nums.length];
        int bestStartIndex = 0;
        for (int i = 1; i < nums.length; ++i) {
            while (i > bestStartIndex + nums[bestStartIndex]) {
                bestStartIndex ++;
            }
            dp[i] = dp[bestStartIndex] + 1;
        }
        return dp[nums.length - 1];
    }
}

3)动态规划优化,需要理解

class Solution {
 
    public int jump(int[] nums) {
        if(nums.length == 1) return 0;
    
        int[] dp = new int[nums.length];//记录的是每个位置最小的跳跃步数
        int[] step = new int[nums.length];//声明一个数组:记录当前跳跃步数,可以到达的最大位置
        step[1] = nums[0];//跳一步能到达的最大位置 ,不会有step[0]
        dp[0] = 0;
        //逻辑还是更新 到达每个位置最小的跳跃步骤
        for(int i = 1;i < nums.length;i++){
            //如果到上一个位置,跳跃的步数,能够到达的最大位置,还能到 i,dp[i]就不变
            if(step[dp[i - 1]] >= i) dp[i] = dp[i - 1];
            else{
                dp[i] = dp[i - 1] + 1;
            }
            //挺牛的优化
            if(dp[i]+1 < nums.length)//防止溢出
            step[dp[i] + 1] = Math.max(step[dp[i] + 1],i + nums[i]);
        }
        return dp[nums.length - 1];
    }
}

作者:188380780
链接:https://leetcode-cn.com/problems/jump-game-ii/solution/tan-xin-shi-yao-de-wo-zhen-de-bu-hui-tan-a-zhi-nen/
来源:力扣(LeetCode)

3)贪心

class Solution {
    public int jump(int[] nums) {
        //当前能够走到的最大下标位置!
        int end = 0;
        //在自己走到这个下标范围内,动态记录下一步能走到的最大位置
        int maxPosition = 0; 
        //记录走的步数
        int steps = 0;

        for (int i = 0; i < nums.length - 1; i++) {
            //一直动态记录:到当前位置的这个区间里,所能到的最大位置下标,其实就是下一步的区间
            maxPosition = Math.max(maxPosition, i + nums[i]); 
            //如果走到了当前区间的边,就加1,因为还要走下一步
            if (i == end) {
                //必然走下一步,就要步子加一
                //并且更新之后的区间范围!
                end = maxPosition;
                steps++;
            }
        }
        return steps;
    }
}

4)还有反方向的贪心,时间复杂度为 O(N²),可看LeetCode答案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值