题目要求

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.

对于类似体型Jump Game I,请参考这篇博客
这题相对于I,差别在于已知一定可以到达终点,找到一条最短路径所需要的步数。

思路一:递归 超时

通过递归的方式找到一条到达终点的路径。通过和当前最短路径比较来省去一些不必要的遍历。但是存在缺点。其实同一个节点到达最终节点的最短步数是一定的,而每一次递归都造成无法省略的重复遍历。

    public int jump(int[] nums) {
        jump(nums, 0, 0);
        return minimumSteps;
    }
    
    public void jump(int[] nums, int currentStep, int currentIndex){
        if(currentIndex + nums[currentIndex] >= nums.length){
            minimumSteps = Math.min(minimumSteps, currentStep+1);
            return;
        }
        if(minimumSteps!=0 && currentStep >= minimumSteps){
            return;
        }
        for(int i = 1; i<=nums[currentIndex] ; i++){
            jump(nums, currentStep+1, currentIndex+i);
        }
    }

思路二:反向动态编程 超时

如果我们从终点往起点寻找,先找可以直接到达终点的最小下标,然后将该下标作为终点,继续查找到达该终点的最小下标,并将step加一。这种代码在大多数情况下,效率正常,但是如果出现极端情况,比如数据量很大,且到达当前终点的最小下标即为当前终点的前一个节点。就会造成非常严重的无用遍历。在最好的情况下的时间复杂度为O(n),但是最差的时间复杂度为O(n^2)

    public int jump2(int[] nums){
        int minimumSteps = 0;
        int last = nums.length - 1;
        while(last != 0){
            int nextLast = last;
            for(int i =last-1 ; i>=0 ; i--){
                if(nums[i] + i >= last){
                    nextLast = i;
                }
            }
            last = nextLast;
            minimumSteps++;
        }
        
        return minimumSteps;
    }

思路三:BFS 广度优先算法

再回到正序遍历,举个例子,输入的数组为[2,3,1,1,4],这时候我们知道0步时的下标为0,1步可以走到的下标包括1,2,2步可以走到的下标为3,4,而4即为我们的终点。
转换为广度优先算法即为:

2   step 0
31  step 1
14  step 2

我们只需要找到每一步的开始节点和结束下标,找到下一轮遍历的最大下标,如果该下标超过了数组长度,那么结束遍历,返回步数,否则将上一轮的最终节点加一作为起始节点,并将下一轮最大下标最为结束节点,继续遍历。

  public int jump3(int[] nums){
        int length = nums.length ; 
        if(length<2) return 0;
        int currentMax = 0, i = 0, nextMax = 0, level = 0;;
        while(currentMax-i+1 > 0){
            level++;
            for( ; i <= currentMax ; i++){
                nextMax = Math.max(nextMax, nums[i]+i);
                if(nextMax>=length-1) return level;
            }
            currentMax = nextMax;
        }
        //说明无法到达终点
        return nextMax>=length-1? level : -1;
    }  

clipboard.png
想要了解更多开发技术,面试教程以及互联网公司内推,欢迎关注我的微信公众号!将会不定期的发放福利哦~


raledong
2.7k 声望2k 粉丝

心怀远方,负重前行