[路飞]_1306. 跳跃游戏 III

1,654 阅读2分钟

「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战

1306. 跳跃游戏 III

题目

这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。

请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。

注意,不管是什么情况下,你都无法跳到数组之外。

示例1

输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案: 
下标 5 -> 下标 4 -> 下标 1 -> 下标 3 
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3 

示例2

输入:arr = [4,2,3,0,3,1,2], start = 0
输出:true 
解释:
到达值为 0 的下标 3 有以下可能方案: 
下标 0 -> 下标 4 -> 下标 1 -> 下标 3

示例3

输入: arr = [3,0,2,1,2], start = 2
输出: false
解释: 无法到达值为 0 的下标 1 处。 

提示

  • 1 <= arr.length <= 5 * 10^4
  • 0 <= arr[i] < arr.length
  • 0 <= start < arr.length

题解

DFS

对于任意位置 idxidx , 可以跳到 arr[idx]+idxarr[idx] + idx 或者 arr[idx]idxarr[idx] - idx , 我们是不是可以从数组下标 startstart 处开始,向arr[idx]+idxarr[idx] + idx或者 arr[idx]idxarr[idx] - idx 深度搜索?可以吧,

伪代码:

dfs(start)
function dfs(idx){
    // 向arr[idx] + idx方向搜索
    dfs(idx + arr[idx])
    
     // 向arr[idx] - idx方向搜索
    dfs(idx - arr[idx])
}

深度递归要有中止条件啊,在这个跳跃游戏中终止条件是什么呢?

题目要求:跳到对应元素值为0的任一下标处,所以递归中止条件是:

dfs(start)
function dfs(idx){
    if(arr[idx] === 0) returndfs(idx + arr[idx])
    dfs(idx - arr[idx])
}

还是不行啊,如果不能跳转到元素值为0的下标呢?比如进入了一个循环,来回循环跳转这么处理呢?

这就需要一个额外数组空间 listlist 存储已经跳转过的路径了,假设已经跳转过的路径,直接返回终止递归

// 初始值额外空间为空
let list = []
dfs(start)
function dfs(idx){
    //  如果额外空间在idx出有值,判定当前下标已经访问过,终止递归
    if(list[idx]) return;
    
    //记录访问过的下标
    list[idx] = 1;
    if(arr[idx] === 0) return
    
    dfs(idx + arr[idx])
    dfs(idx - arr[idx])
}

arr[idx]+idxarr[idx] + idx或者 arr[idx]idxarr[idx] - idx 深度搜索,arr[idx]+idxarr[idx] + idx或者 arr[idx]idxarr[idx] - idx 可能会出现数组越界呀。所以需要再加判断,如果idx越界,终止递归

// 初始值额外空间为空

dfs(start)
function dfs(idx){
    //  如果idx越界,终止递归
    if( idx < 0 || idx >= len) return
    
    dfs(idx + arr[idx])
    dfs(idx - arr[idx])
}

综上所述思路编辑代码如下

完整代码

var canReach = function (arr, start) {
  const len = arr.length;
  const list = Array(len).fill(0);
  return dfs(start);
  function dfs(idx) {
    if (arr[idx] === 0) return true;
    if (list[idx]) return false;
    list[idx] = 1;
    if (idx < 0 || idx >= len) return false;
    return dfs(idx + arr[idx]) || dfs(idx - arr[idx]);
  }
};

BFS

理解了DFS就比较容易理解BFS了。

  • 使用 stackstack 存储可以访问的数组下标队列
  • stackstack 取一位数组下标idxidx,计算 arr[idx]+idxarr[idx] + idx或者 arr[idx]idxarr[idx] - idx
  • 如果arr[idx]+idxarr[idx] + idx或者 arr[idx]idxarr[idx] - idx 没有越界,没有访问过,将数据添加到 stackstack
  • 直到 stackstack 为空,或者找到元素为0的下标
  • 返回结果

完整代码

var canReach = function (arr, start) {
  const len = arr.length;
  const list = Array(len).fill(0);
  const stack = [start];
  while (stack.length) {
    const p = stack.pop();
    if (arr[p] === 0) return true;
    const left = p + arr[p];
    if (left >= 0 && left < len && list[left] === 0) {
      stack.push(left);
      list[left] = 1;
    }
    const right = p - arr[p];
    if (right >= 0 && right < len && list[right] === 0) {
      stack.push(right);
      list[right] = 1;
    }
  }
  return false;
};