1. 程式人生 > >Leetcode 45:跳躍遊戲 II(最詳細的解法!!!)

Leetcode 45:跳躍遊戲 II(最詳細的解法!!!)

給定一個非負整數陣列,你最初位於陣列的第一個位置。

陣列中的每個元素代表你在該位置可以跳躍的最大長度。

你的目標是使用最少的跳躍次數到達陣列的最後一個位置。

示例:

輸入: [2,3,1,1,4]
輸出: 2
解釋: 跳到最後一個位置的最小跳躍數是 2。
     從下標為 0 跳到下標為 1 的位置,跳 1 步,然後跳 3 步到達陣列的最後一個位置。

說明:

假設你總是可以到達陣列的最後一個位置。

解題思路

這個問題是之前Leetcode 55:跳躍遊戲(最詳細的解法!!!)的提升。我們先看看這個問題能不能通過動態規劃解決,很簡單,只是對之前的問題稍加修改,我們這裡要考慮的問題是到index

的最小步數,也就是之前的[0:index-1]中向前一步能到達index的最小值。

我們在初始化的時候將mem全部初始化為inf,而mem[0]=0即可。

class Solution:
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)
        mem = [float('inf')]*nums_len
        mem[0] = 0
        for i in range
(1,nums_len): for j in range(i): if nums[j] + j >= i: mem[i] = min(mem[j]+1, mem[i]) break return mem[-1]

但是這樣寫法超時了,原因和之前問題一樣,一定是有些可以剪枝的思路沒有考慮到。我們如果按照之前思路,將這個問題反過來考慮的話,也就是

class Solution:
    def jump(self, nums)
: """ :type nums: List[int] :rtype: int """ nums_len = len(nums) mem = [float('inf')]*nums_len mem[0] = 0 for i in range(1,nums_len): for j in range(i, -1, -1): if mem[j] != float('inf') and nums[j] + j >= i: mem[i] = min(mem[j]+1, mem[i]) break return mem[-1]

但是這樣思考對嗎?對於上面的例子

2   3   1   1   4
0   1

我們考慮1,如果用我們上面寫的程式碼的話,這裡我們就需要2步到1,而實際上只要1步,原因在於我們break了,我們沒有繼續向前查詢更小的了。break去了就可以了嗎?實際上這又回到了最原始的程式碼,沒有任何剪枝的考量,顯然是不合理的。

這個問題通過貪心演算法能否解決呢?我們前面步子儘量邁大一點,後面就有更多的空間了啊?顯然這種做法是不可行的,因為我們每次求解的是區域性最優解,而對於全域性來說就不一定是最優解了。那是不是不能用貪心了?我們可以換一個思路,我們先思考跳一步的話最遠可以跳多遠,接著思考跳兩步的話最遠可以跳多遠,以此類推直到最遠的距離大於等於nums.size()-1,那麼此時的步數自然就是最少的步數。

所以我們先遍歷一遍nums,對於每個index,我們要判斷當前steps[step]是不是能大於等於nums_len-1,如果成立,那麼我們只要step+1步即可。如果steps[step]<index,也就是說當前step步無法到達index這個位置,我們就要多跳一步step+1。對於我們下一步可以跳多遠steps[step+1]這個問題,自然是i in range(index)這個區間內max(nums[i]+i)所決定的,這也是之前問題Leetcode 55:跳躍遊戲(最詳細的解法!!!)中的思想。

class Solution:
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        nums_len = len(nums)       
        steps, step = [nums[0]]*nums_len, 0
        for i in range(1, nums_len):
            if steps[step] >= nums_len - 1:
                return step + 1
            if steps[step + 1] < i + nums[i]:
                steps[step + 1] = i + nums[i] 
            if steps[step] <= i:
                step += 1  
                
        return step

非常簡潔,非常酷!!!

我將該問題的其他語言版本新增到了我的GitHub Leetcode

如有問題,希望大家指出!!!