问题:Jump Game I
难度:medium
说明:
给出一个 数组,数组内 数字 表示可以往前跳 0 ~ N 格, 如果能够跳到终点就返回 true,不能 false。
题目连接:https://leetcode.com/problems/jump-game/
输入范围:
1 <= nums.length <= 3 * 10^4
0 <= nums[i][j] <= 10^5
输入案例:
Example 1:
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
我的代码:
这个我处理起来就随便点了,因为可以跳 0 ~ N 格,那我每次都跳一格,然后发现了 0 ,就马上回退,看看那个地方可以跳过 0 这个坑就行了。其实还可以优化,不用重复计算。
class Solution {
public boolean canJump(int[] nums) {
int len = nums.length, len1 = len - 1;
A:for(int i = 0;i < len;i ++)
if(nums[i] == 0 && i != len1) {
for(int j = i;j -- > 0;) // 发现坑,就马上回跳
if(nums[j] > i - j) continue A;
return false; // 如果会跳没找到一个适合的就退出
}
return true;
}
}
问题:Jump Game II
难度:hard
说明:
给出一个 数组,数组内 数字 表示可以往前跳 1 ~ N 格, 假设一定会跳到终点, 求跳跃的最少次数。
题目连接:https://leetcode.com/problems/jump-game-ii/
输入范围:
1 <= nums.length <= 3 * 104
0 <= nums[i] <= 105
输入案例:
Example 1:
Input: nums = [2,3,1,1,4]
Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: nums = [2,3,0,1,4]
Output: 2
我的代码:
有点难度,不过如果学过 KMP 的话,前缀函数的思想应该可以解决,如果用 全排列,把 1 ~ num[i] 情况用 dfs (递归 + 遍历)都处理一遍,这种阶乘的时钟周期绝对超时,但是如果想到 前缀函数,就是使用分治法,避免重复计算,并且利用前一个已经得出最短路径结果再进行一次计算,可能会很简单。
1、用一个 jump 存放 跳跃索引。
2、从尾部开始遍历,从尾部找到最长可跳跃到达的索引,然后存放。
3、如果找到可跳跃索引 == jump[j],就存放 jump[j],否则存放最长跳跃索引 j。
class Solution {
public int jump(int[] nums) {
int len = nums.length;
int[] jump = new int[len];
jump[len - 1] = len - 1;
for(int i = len - 1; i -- > 0;) { // 思路类似于前缀索引
int j = i + 1;
int temp = nums[i] + i;
while(j < len && temp > jump[j ++]); // 利用前一次结果, 找出更少的一步
j --; // 每次都会多出 1
if(temp == jump[j]) jump[i] = jump[j]; // 结果如果和 jump 的索引一致,先使用索引
else jump[i] = j; // 否则使用 j
}
int begin = 0, times = 0;
while(true) { // 无非再跳一次
if(begin == len - 1) break;
begin = jump[begin];
times ++;
}
return times;
}
}
问题:Jump Game III
难度:medium
说明:
给出一个 数组,和开始索引,从开始索引出发,能够左跳或者右跳,如果能够移动到数组内数值为 0 的位置,就返回true,否则返回 false。
题目连接:https://leetcode.com/problems/jump-game-iii/
输入范围:
1 <= arr.length <= 5 * 10^4
0 <= arr[i] < arr.length
0 <= start < arr.length
输入案例:
Example 1:
Input: arr = [4,2,3,0,3,1,2], start = 5
Output: true
Explanation:
All possible ways to reach at index 3 with value 0 are:
index 5 -> index 4 -> index 1 -> index 3
index 5 -> index 6 -> index 4 -> index 1 -> index 3
Example 2:
Input: arr = [4,2,3,0,3,1,2], start = 0
Output: true
Explanation:
One possible way to reach at index 3 with value 0 is:
index 0 -> index 4 -> index 1 -> index 3
Example 3:
Input: arr = [3,0,2,1,2], start = 2
Output: false
Explanation: There is no way to reach at index 1 with value 0.
我的代码:
这个跟全排列一个意思,然后我来个缓存 cacheMap,防止重复计算就行。
class Solution {
private HashMap<Integer, Boolean> cache = new HashMap<>(); // 缓存
public boolean canReach(int[] arr, int start) {
return recurtion(arr, start, arr.length, new boolean[arr.length]);
}
public boolean recurtion(int[] arr, int start, int len, boolean[] visited) {
if(start >= 0 && start < arr.length && !visited[start]) {
visited[start] = true; // 避免跳重复了
boolean reach = arr[start] == 0 // 查看是否到达了 0
|| cache.getOrDefault(start, false) // 防止重复计算
|| recurtion(arr, start + arr[start], len, visited) // 左跳
|| recurtion(arr, start - arr[start], len, visited); // 右跳
visited[start] = false;
cache.put(start, reach);
return reach;
}
return false;
}
}