方法一,递归
解题思路
- 建立一个映射表,初始值皆为0。
- 做以下约定:
1表示该下标值是通的,也即能到达nums最后一个值;
-1表示该下标的路是不通的;
0表示不清楚通不通。
- 注意,这里要等于,maxJump遍历时需要遍历最后一个下标
对于[3,2,0,4],下面这个算法会走这个流程
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)
};
超时了。当数组长度巨长时,递归就寄了。
当数组没那么长时就能顺利通过
-
例子1
-
例子2
-
例子3
方法二,从后往前遍历
解题思路
- 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…
方法三,一次遍历搞定
解题思路
- 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
};