为了给刷题的同学一些奖励,力扣团队引入了一个弹簧游戏机。游戏机由 N 个特殊弹簧排成一排,编号为 0 到 N-1。初始有一个小球在编号 0 的弹簧处。若小球在编号为 i 的弹簧处,通过按动弹簧,可以选择把小球向右弹射 jump[i] 的距离,或者向左弹射到任意左侧弹簧的位置。也就是说,在编号为 i 弹簧处按动弹簧,小球可以弹向 0 到 i-1 中任意弹簧或者 i+jump[i] 的弹簧(若 i+jump[i]>=N ,则表示小球弹出了机器)。小球位于编号 0 处的弹簧时不能再向左弹。
为了获得奖励,你需要将小球弹出机器。请求出最少需要按动多少次弹簧,可以将小球从编号 0 弹簧弹出整个机器,即向右越过编号 N-1 的弹簧。
示例 1:
输入:jump = [2, 5, 1, 1, 1, 1]
输出:3
解释:小 Z 最少需要按动 3 次弹簧,小球依次到达的顺序为 0 -> 2 -> 1 -> 6,最终小球弹出了机器。
限制:
1 <= jump.length <= 10^6
1 <= jump[i] <= 10000
思路:比赛时采用的BFS,下来后发现榜单前几名几个大佬的做法,学到了很多,下面对着某位大佬的思路改写了自己的方法。大致思路是一样的。
该题完全可以通过模拟整个跳跃过程,对于当前位置i我们下步的选择无非是走到i+jump[i],或者跳到i左边任意一个位置上,一个简单的思路就是通过BFS来枚举下步的状态,通过保存每次所能跳的最远点使得优化状态的遍历。这个解法相信比赛中大多数人都可以想得到的。我们要知道下一步要走的点一定是之前没走过的点,因为若下个点走过,说明我通过更优的方法已经走到了呢个点,完全没必要再绕远路过去,因此我们可以模拟每次走的点,并按顺序加入队列中,最终通过遍历所有状态找到最优解(第一次跳出去所使用的步骤一定是最小步骤)。
class Solution {
public int minJump(int[] jump) {
int i=0;
int n=jump.length,head=0;
int[] d=new int[n];
int[] q=new int[n];
Arrays.fill(d, -1);
int l=0,r=0;
d[0]=0; q[r++]=0;
while(l!=r) {
i=q[l++];
if(i+jump[i]>=n) break;
if(d[i+jump[i]]==-1)
d[q[r++]=i+jump[i]]=d[i]+1;
for(;head<i;head++)
if(d[head]==-1)
d[q[r++]=head]=d[i]+1;
}
return d[i]+1;
}
}