这是我参与2022首次更文挑战的第23天,活动详情查看: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
思路
首先我们得写一个方法,让它去执行跳跃的动作,每一次到达一个节点的时候,我们需要分类讨论:
-
如果当前的节点值是
0
,那么说明我们找到了终点,直接返回true
; -
往左边跳跃之前,我们需要先判断元素跳跃出去的位置是否超出我们的索引范围,左边界的索引值是
0
,如果跳跃完索引所在的位置大于等于0
,说明可以往左跳,判断跳跃的结果即可;、 -
往右边跳跃之前,我们同样判断元素跳跃出去的位置是否超出边界,右边界的索引值是
n-1
,如果跳跃完索引所在的位置小于n
,说明可以往右跳,判断跳跃的结果即可; -
为了防止出现无限循环的情况,我们需要用一个索引数组,来记录每个元素是否跳跃过,初始值为
0
,每次跳跃的时候把值修改成1
,然后在往左和往右跳跃之前,我们先判断下一个节点我们之前是否有来过,如果来过了就不用跳过去了; -
最终我们先尝试往左边跳的所有可能,如果跳不出去再尝试往右边跳的所有可能,左右两边都试过还不行的话说明就是真的不行了。
实现
/**
* @param {number[]} arr
* @param {number} start
* @return {boolean}
*/
var canReach = function(arr, start) {
const n = arr.length;
// 记录每个节点是否跳跃过
const list = new Array(n).fill(0);
// 执行跳跃的方法
function findNextIndex(arr, start) {
// 如果找到了我们要的节点,就不用跳了
if (arr[start] === 0) {
return true;
}
// 当前坐标标识一下,我们来过,防止重复跳跃
list[start] = 1;
// 如果往左跳不超过边界,同时左边落脚点我们没去过,那么就跳过去看看
if (
start - arr[start] >= 0
&& list[start - arr[start]] === 0
&& findNextIndex(arr, start - arr[start])
) {
return true;
}
// 往右跳也是一样的逻辑,都尝试一遍
if (
start + arr[start] < n
&& list[start + arr[start]] === 0
&& findNextIndex(arr, start + arr[start])
) {
return true;
}
// 往左往右都尝试过了,都不行
return false;
}
return findNextIndex(arr, start);
};
复制代码
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。