1. 问题描述:
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game
2. 思路分析:
① 读完题之后可以发现这个道题目的本质是bfs,其中典型的特点是从原状态到目标状态的所需要的最少步骤,只是这里改变了一下问题求解的东西,求解的是能否到达最后的目标状态,但是本质上求解的是一个东西,典型的bfs题目,可以来说比较简单,使用bfs的常规操作加上题目的要求即可完成
② bfs典型的解决是使用一个队列,我们可以创建一个内部类来表示当前的节点,节点需要一个属性表示当前节点的位置,队列的数据类型为当前的节点类型,因为这里只是涉及到了当前节点的位置所以也可以将Queue队列的元素数据类型为Integer,只是之前使用bfs的时候习惯使用了内部类,将开始节点加入到队列中,当队列非空的时候执行循环,在循环一开始弹出队列的元素,在for循环中判断当前位置能否能够到达在其后面的位置,假如能够到达其他的位置将这个节点加入到队列中并且将该位置的标记数组对应的位置赋值为1,标记数组主要是为了重复访问之前已经访问过的位置,因为假如之前能够到达这个位置说明这个之前这个方案的路径是最短的,之后也到达这个位置但是已经被标记了说明不是最短的
③ 在循环一开始弹出节点的时候判断当前元素的位置是否是数组长度减1,假如是说明能够到达,对于这种bfs题目做多了自然会形成条件反射,因为题目中蕴含着非常明显使用bfs解决的一个特点,然后结合bfs的套路和题目的要求就可以轻松解决了
3. 代码如下:
class Solution {
public class Node{
private int pos;
/*当前节点的位置*/
public Node(int pos) {
this.pos = pos;
}
}
public boolean canJump(int[] nums) {
int len = nums.length;
Queue<Node> queue = new LinkedList<>();
queue.add(new Node(0));
/*标记数组用来标记已经被访问过的位置先标记过的说明之前到达这个节点的路径比较短*/
int vis[] = new int[len];
vis[0] = 1;
while (!queue.isEmpty()){
Node poll = queue.poll();
int curPos = poll.pos;
if (curPos == len - 1) return true;
for (int i = 1; i <= nums[curPos]; ++i){
/*未被访问过*/
if (curPos + i < len && vis[curPos + i] != 1){
Node newNode = new Node(curPos + i);
queue.add(newNode);
//标记已经被访问过了
vis[curPos + i] = 1;
}
}
}
return false;
}
}