Leetcode 55:跳躍遊戲(最詳細的解法!!!)
阿新 • • 發佈:2018-11-12
給定一個非負整數陣列,你最初位於陣列的第一個位置。
陣列中的每個元素代表你在該位置可以跳躍的最大長度。
判斷你是否能夠到達最後一個位置。
示例 1:
輸入: [2,3,1,1,4]
輸出: true
解釋: 從位置 0 到 1 跳 1 步, 然後跳 3 步到達最後一個位置。
示例 2:
輸入: [3,2,1,0,4]
輸出: false
解釋: 無論怎樣,你總會到達索引為 3 的位置。但該位置的最大跳躍長度是 0 , 所以你永遠不可能到達最後一個位置。
解題思路
這個問題非常簡單,我們通過遞迴很容易解決。我們想要知道能否到達index
,那麼只需要知道index
nums[i]+i >= index for i in range(index)
,也就是index
之前是不是有元素可以到達index
,如果存在,那麼我們只需要判斷是否有元素能到i
,如果也成立,那麼我們返回True
,否則我們返回False
。例如
3 2 1 0 4
|<- i ->| index
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums_len = len(nums)
return self._canJump(nums, nums_len - 1)
def _canJump(self, nums, index):
if index == 0:
return True
for i in range(index):
if nums[i] + i >= index and self._canJump(nums, i):
return True
return False
我們也很容易通過記憶化搜尋的方法對這個問題優化
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums_len = len(nums)
mem = [None]*nums_len
mem[0] = True
return self._canJump(nums, nums_len - 1, mem)
def _canJump(self, nums, index, mem):
if mem[index] != None:
return mem[index]
for i in range(index):
if nums[i] + i >= index and self._canJump(nums, i, mem):
mem[i] = True
return True
mem[i] = False
return False
但是這種做法在提交的時候超時了,我們只能想其他的辦法。有沒有更好的呢?我們想想通過動態規劃能否解決這個問題,其實思路和記憶化搜尋是一樣的。
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums_len = len(nums)
mem = [False]*nums_len
mem[0] = True
for i in range(1,nums_len):
for j in range(i):
if mem[j] and nums[j] + j >= i:
mem[i] = True
break
return mem[-1]
所以可想而知這樣做也就超時了,顯然我們應該是忽略了什麼可以剪枝的條件。實際上,我們只要反過來思考就可以了。對於能否到達index
的這個問題,我們需要知道對於0<=i<index
是否可以到達index
,並且同時我們能否到達i
。這個時候,我們i
不是從頭開始考慮,而是從後往前考慮的話,會節省大量的時間。例如
1 1 1 1 1 1
index
true ?
我們這是時候知道可以到達index-1
了,我們只需要知道index-1
能否到達index
就可以啦。而不是又要從頭開始遍歷一次。所以只要將程式碼稍微修改一下即可。
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
nums_len = len(nums)
mem = [False]*nums_len
mem[0] = True
for i in range(1,nums_len):
for j in range(i,-1,-1):
if mem[j] and nums[j] + j >= i:
mem[i] = True
break
return mem[-1]
同樣的修改對於記憶化搜尋也是有效的。
對於這個問題最好的解法是貪心演算法。對於index
的位置,我們將index
之前的元素值和其索引值相加
3 2 1 0 4
3 3 3 3 index
然後我們計算之前和的最大值m
,如果index>m
,那麼自然不能到達index
了。對於所有[0:len(nums))
都滿足上述條件的話,那麼自然就成立了。
總體的思路就是,我們希望前面的步子邁大一點,這樣可以給後面留有更多的餘地。
class Solution:
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
m = 0
for i, num in enumerate(nums):
if i > m:
return False
m = max(m, i + num)
return True
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!