LeetCode 45. Jump Game II
Problem LeetCode 45. Jump Game II
1. 题目简述 给出一个整形非负数组,初始在index为0的位置,每个位置上的数代表其所能跳跃的最大长度(不是只能跳跃该长度),保证一定能够跳到末尾节点,求从0节点跳到末尾节点的最少跳跃次数。例如:
Input: [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.
2. 算法思路 Brute Force 首先,暴力求解法直接pass,我们需要遍历所有的步长,我们假设F(x)为从index为x的节点到末尾节点的最短jump数。暴力求解法伪代码:
1 2 3 4 5 6 7 F(x): if x >= n - 1 return 0 ; maxStep = nums[x]; for i from 1 to maxStep: memo[x] = min(memo[x], F(x + i) + 1 ) return memo[x]
Dynamic Programming 这里我们也可以用DP来减少重复计算,对于每个节点到末尾节点最少跳跃次数设为函数F(x),用memo数组来进行记录并更新。下面是top-down和bottom-up的两种算法。
DP1 top-down:
记录一个memo数组,长度为n,每个元素初始化为n(因为数组长度为n,最多跳跃次数也不过是n-1),计算F(0),对于每个0节点能到达的步长,进行比较,记录,找出最小的那个+1即为0节的最少跳跃数。
DP2 bottom-up: 记录一个memo数组,bottom-up算法就是要从base case开始进行计算,一直到目标target,本题中,base case是memo[n-1]=1,所以我们要从n-2开始往回遍历,判断n-2节点能否到达n-1节点,如果能,则memo[n-2]=1,不能则为0,一直遍历到memo[0],返回memo[0]。
两种DP算法时间复杂度均为O(n^2),空间复杂度为O(n)。
Greedy 本题是要找最少的跳跃步数,也就是说我们希望每一步都尽可能要跳得远,步子迈得大。举个例子: [2,3,1,1,4],我们在0节点时,最大步长为2,因此最元能到达1和2两个节点,其最大步长分别为3和1,如果我们想走得远,我们当然希望能够第一次走到1节点,它的最大步长为3,可以到达4节点。
因此我们可以看出,对于初始节点0,它能够到达的最远为farthest为end,然后我们从0到end遍历找出其中x节点能跳到最远距离新的farthest,本次跳跃就跳到x节点,jump++,新的end为farthest,以此类推。直到最后,返回jump值。
3. 解法
暴力解法(Pass,上面有伪代码)
DP top-down
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public int jump (int [] nums) { int n = nums.length; int [] memo = new int [nums.length]; Arrays.fill(memo, n); return minimumJump(nums, 0 , memo); } private int minimumJump (int [] nums, int x, int [] memo) { int n = nums.length; if (x >= n - 1 ) { return 0 ; } if (memo[x] < n) { return memo[x]; } int maxStep = nums[x]; for (int i = 1 ; i <= maxStep; i++) { memo[x] = Math.min(memo[x], minimumJump(nums, x + i, memo) + 1 ); } return memo[x]; } }
DP bottom-up
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int jump (int [] nums) { int n = nums.length; int [] memo = new int [nums.length]; Arrays.fill(memo, n); memo[n - 1 ] = 0 ; for (int i = n - 2 ; i >= 0 ; i--) { int maxStep = nums[i]; for (int j = 1 ; j <= maxStep; j++) { if (i + j > n - 1 ) { break ; } memo[i] = Math.min(memo[i], memo[i + j] + 1 ); } } return memo[0 ]; } }
Greedy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public int jump (int [] nums) { int currEnd = 0 , farthest = 0 , jump = 0 ; for (int i = 0 ; i < nums.length - 1 ; i++) { farthest = Math.max(farthest, i + nums[i]); if (i == currEnd) { currEnd = farthest; jump++; } } return jump; } }