跳跃游戏的多种解法

114 阅读1分钟

方法一,递归

解题思路

  • 建立一个映射表,初始值皆为0。
  • 做以下约定:
1表示该下标值是通的,也即能到达nums最后一个值;
-1表示该下标的路是不通的;
0表示不清楚通不通。
  • 注意,这里要等于,maxJump遍历时需要遍历最后一个下标

对于[3,2,0,4],下面这个算法会走这个流程

image.png

var canJump = function(nums) {
    /**
        建立一个映射表,初始值皆为0。
        做以下约定:
        1表示该下标值是通的,也即能到达nums最后一个值;
        -1表示该下标的路是不通的;
        0表示不清楚通不通。

        注意,这里要等于,maxJump遍历时需要遍历最后一个下标
     */
    let map = Array(nums.length).fill(0)
    map[nums.length-1] = 1
    function jump(index) {
        if(map[index] === 1) {
            return true
        }
        // if(map[index] === -1) {
        //     return false
        // }
        // maxJump表示能跳跃的最大下标。其实,如果maxJump大于等于num.length - 1,就已经说明是通的了。
        let maxJump = Math.min(index + nums[index], nums.length-1) 
        for(let i = index + 1; i <= maxJump; i++) {
            let jumpResolt = jump(i)
            console.log(jumpResolt)
            if(jumpResolt === true) {
                nums[i] = 1
                return true
            }
        }

        // 当nums长度为0时;或当jumpResolt 都不为 true,也就是遍历结束也没中断过。则走下面代码
        map[index] = -1
        return false
    }

    return jump(0)
};

超时了。当数组长度巨长时,递归就寄了。

image.png

当数组没那么长时就能顺利通过

  • 例子1 image.png

  • 例子2 image.png

  • 例子3 image.png

方法二,从后往前遍历

解题思路

  • 1.建立memo数组记录是否能通。其中通为1,不通为0
  • 2.最后一个值肯定是通的
  • 3.外层从后往前遍历,同时内部从当前下标往后遍历,此时计算遍历的最远距离,若找到标记为1的值,则说明当前下标是通的。 此时,break中断当前循环,循环不用再往下走了

这里代码变得相对简单了。

var canJump = function(nums) {
    let memo = Array(nums.length).fill(0)
    memo[nums.length - 1] = 1
    // 从后往前遍历,
    // 同时内部从当前下标往后遍历,此时计算遍历的最远距离,若找到标记为1的值,则说明当前下标是通的。
    // 此时,break中断当前循环,循环不用再往下走了
    for(let i = nums.length -2; i >= 0; i--) {
        let maxJump = Math.min(nums.length - 1, i + nums[i]) // 注意这里去最小值
        for(j = i; j <= maxJump; j++) {
            console.log(maxJump,memo[i], memo[j])
            if(memo[j] === 1) {
                memo[i] = 1
                break
            } 
        }
    }

    return memo[0] === 1
};

进行官方的这个示例是,寄了,超时了。 leetcode.cn/submissions…

image.png

方法三,一次遍历搞定

解题思路

  • 1.从后往前遍历
  • 2.定义能通过的下标,用passIndex表示。初始值就是nums最后一个值的下标
  • 3.每次遍历看看是否要更新passIndex,更新的条件是要当前下标与值的和大于等于passIndex,注意,这里需要包含等于的条件!!
  • 4.遍历结束看passIndex是否为0,也就是第一个元素是否是通的
/**
 * @param {number[]} nums
 * @return {boolean}
 */
var canJump = function(nums) {
    // 当前通的下标
    let passIndex = nums.length - 1
    for(let i = nums.length -2; i >= 0; i--) {
        if(i + nums[i] >= passIndex) { // 注意:通过的条件是包含等于的!!
            passIndex = i
        }
    }

    return !passIndex
};