題目地址:
https://leetcode-cn.com/probl...
題目描述:java
給定一個非負整數數組,你最初位於數組的第一個位置。 數組中的每一個元素表明你在該位置能夠跳躍的最大長度。 你的目標是使用最少的跳躍次數到達數組的最後一個位置。 示例: 輸入: [2,3,1,1,4] 輸出: 2 解釋: 跳到最後一個位置的最小跳躍數是 2。 從下標爲 0 跳到下標爲 1 的位置,跳 1 步,而後跳 3 步到達數組的最後一個位置。
解答:
和第55題同樣,首先試一下動態規劃dp[i]表明到座標爲i的節點所用的最短步驟。
那麼dp[0] = 0,dp[i] = min(dp[i-k]+1) , k >= 0 而且 k <= i-1,而且nums[k]+k >= i。
不過惋惜的是複雜度過大,爲O(N²),用例不經過。segmentfault
換一種思路,這個和第55題同樣,這是個貪心問題,用一個max變量記錄當前可以到達的最遠節點。那麼初始時
max = nums[0],對於i=1...nums.length-1,若是nums[i]+i > max(即該節點可以到達比max更遠的節點)
就更新max,而且把dp[max+1]...dp[nums[i]+i]更新爲dp[i]+1不然跳過。這樣一來,每個節點只計算一次。
也只訪問一次,時間複雜度爲O(N)。數組
java ac代碼:code
class Solution { public int jump(int[] nums) { int[]dp = new int[nums.length]; //用這個最大值代替優先隊列,由於效果是同樣的 //用優先隊列保存已經求出的最大下標也能夠,可是 //每次都是從小到大求,因此每次求出更新max便可 //保持是最大的,不須要使用優先隊列。 int max = nums[0]; for(int i = 1;i < nums.length && i <= nums[0];i++) { dp[i] = 1; } for(int i = 1;i < nums.length;i++) { for(int k = max+1;k < nums.length&&k<=i+nums[i];k++) { dp[k] = dp[i]+1; max = k; } } return dp[nums.length-1]; } }
動態規劃超時代碼:隊列
class Solution { public int jump(int[] nums) { int[] dp = new int[nums.length]; dp[0] = 0; for(int i = 1;i < nums.length;i++) { int temp = Integer.MAX_VALUE; for(int k = i-1;k >= 0;k--) if(nums[k] >= i-k) temp = Math.min(temp,dp[k]); dp[i] = temp+1; } return dp[nums.length-1]; } }