45. Jump Game II

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position.

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

Note:

You can assume that you can always reach the last index.


题意很简单,给定一个数组,从第一个元素开始跳,每次跳的距离不能大于该元素的值,请问最少要跳几次才能到数组末尾。


看完题目之后,第一个想法是联想到了之前某个公司实习生笔试做过的一个题目:九宫格。因此,脑子里的解题思路就是使用BFS,我们可以把每种跳的情况都遍历一次,那种路径最先到达终点,该路径跳的次数就是我们所要求的答案。

下面是使用BFS算法代码


public class Solution {
    public int jump(int[] nums) {
        if(nums.length==1) return 0;
        int[] jumps = new int[]{0};//jumps数组用来计算跳的次数
        LinkedList<Integer> q = new LinkedList<>();//用来存储起跳的位置(数组下标)
        q.offer(0);
        fon(nums,jumps,q);
        return jumps[0];
    }
    public void fon(int[] nums, int[] jumps,LinkedList<Integer> q){
        LinkedList<Integer> q1 = new LinkedList<>();
        for(int s : q){
            
            if(nums[s] >= nums.length-s-1){         //如果能一步到终点,那么递归结束
                jumps[0]++;
                return;
            }else{
                for(int i=0;i<nums[s];i++){      //否则的话,我们把下一次起跳的位置保存起来
                if(!q1.contains(s+i+1))
                    q1.offer(s+i+1);
                }
            }
        }
        jumps[0]++; //起跳次数加一
        fon(nums,jumps,q1);    //递归
    }
}
这种方法理论上是可行的,但是在提交的时候显示TLE以及栈溢出。通过查看测试数据,得到原因有以下2点

1.我们做了很多无用功,有比较大的一部分路径是显然跳的次数比其他路径多,比如数组{2,1,3,4,5},在第二次起跳时,按照上述算法,我们需要计算从1起跳和从3起跳2种情况,但是事实上从1起跳之后只能到3,毫无疑问次数比直接从3起跳要多1次,因此这种情况应该直接排除。

2.当数组中全部是1时,我们不应该继续使用递归,因为此时,只能有1种跳的方式,就是向前跳一步。

基于上述2种原因,我们把算法改进

public class Solution {
    public int jump(int[] nums) {
        if(nums.length==1) return 0;
        int[] jumps = new int[]{0};
        int s = 0;    //此处改为int变量即可
        fon(nums,jumps,s);
        return jumps[0];
    }
    public void fon(int[] nums, int[] jumps,int s){
            while(nums[s] == 1){                  //处理数组元素是1的特殊情况
                if(nums[s] >= nums.length-s-1){
                jumps[0]++;
                return;
                }
                jumps[0]++;
                s++;
            }
            if(nums[s] >= nums.length-s-1){
                jumps[0]++;
                return;
            }else{
                int max = 0,index = 0;
                for(int i=0;i<nums[s];i++){         //我们循环得到下一步走的最远的数组下标,这是算法核心
                    if(s+i+1+nums[s+i+1] > max){
                        max = s+i+1+nums[s+i+1];
                        index = s+i+1;
                    } 
                }
                s = index;
            }
        jumps[0]++;
        fon(nums,jumps,s);
    }
}

此时解法可以AC,并且在LeetCode上排名超过了90.99%,这是一个不错的成绩。再来看一下最终解法,其实就是一个 贪心的思想。我们只要保证下一步能够走的最远,就能保证最终跳的次数最少。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值