LeetCode Medium 55 跳躍遊戲 Python
方法一:
演算法:貪心
首先要明確如何向後跳是一個好的選擇,從某個位置i向後跳的時候,可以選擇的位置有nums[i]個(nums[i]儲存
了第i個位置可以向後跳的步數)。應當選擇這nums[i]個位置中,又可以向後跳到最遠位置的那個位置處:
解釋:
譬如當前位置為i=0,可以向後跳3步,即從i=0出發最遠可以到達j=0+3=3的位置,那麼下一步如何跳要
考察i+1,i+2,i+3這三個位置可以跳到的最遠處,譬如這三個位置最遠可達位置分別為4,6,3,那麼
下一步應該跳到i+2這個位置,因為這個位置可以到達位置i=6這裡
且若此時在i處,最遠可達j,則一定可以到達i+1,i+2,...,j-1,j處
解題:
1. 建立"最遠可達陣列",即i+nums[i],求得nums中每個位置最遠可達位置
2. 設定curr=0起跳位置,以及當前最大可達位置max_reach,curr的意義就是逐個向後走,在最大可達
位置內挪動,如i=0可達4,那麼curr一定可以向後走到i=1,2,3,4。當curr走到i=1,2,3,4的途中,應該
判斷當前最大可達位置是否變大了,如果變大了就可以繼續curr += 1一步一步向後走並更新最大可達位置
(上面提過了,因為如果可以從i到達j,那麼一定可以到i+1,i+2,...,j-1,j處,所以走到i處時,max_reach
變了,就更新為更大的max_reach,curr++直到<=max_reach)
所以可以設定curr記錄當前到達位置,並且逐步向後移
3. 令curr開始挪動,判斷是否能抵達陣列末尾,向下一個位置移動的條件是當前所在位置沒有超過當前
最大可達位置,並且curr當前位置應該是小於陣列長度的
4. 跳出迴圈後,curr記錄的就是最後到達的位置,如果到達的位置就是陣列末尾,也就是說在最大可達範圍內
一步一步走到了最後的陣列末尾,則返回True否則False
注意:
我自己想的"解法"是,同樣地也算出來reach陣列記錄每個位置能到達的最遠位置,那麼逐個遍歷去判斷陣列
內的最大可達位置是否有一個reach[x] >= len(nums)-1 的不就好了,即陣列中有一個位置是到達該位置
後一定可以到達陣列末端的,但是!這樣的想法忽略了【跳躍】的概念,即首先你得能到達那個可達陣列末端
的節點,如[1,1,0,0,999,999,1],因為中間有0,且前面的1,1不給力,雖然後面有999這種肯定能到達
末端的位置,但是根本無法從i=0處跳到999,所以要用上面【解題】中的方法,在最大可達位置中curr += 1
複雜度分析:
時間:ON,建立輔助陣列ON,curr挪動遍歷一遍陣列ON
空間:ON,記錄最大可達位置的輔助陣列
def canJump(self, nums):
if nums == []:
return False
reach = []
for i in range(len(nums)):
reach.append(i + nums[i])
curr = 0
max_reach = reach[0]
while curr < len(nums) and curr <= max_reach:
if reach[curr] > max_reach:
max_reach = reach[curr]
curr += 1
return curr == len(nums)
方法二:
演算法:貪心2-逆向思維
反過來思考整個跳躍的過程,如果能從某一個節點跳躍到達最後一個節點,那麼從最後一個節點回看,一定能
到達第一個初始節點。
思路:
如果有一條路徑A->B->C->D->FINAL,即最後到達FINAL,那麼從FINAL開始向前看,若D是能到達FINAL的,
那麼前面的位置只要能到達D就是到達FINAL的充分條件了,能到達D則一定能到達FINAL,倒著來看!
所以倒著遍歷陣列,設定一個last位置為最後一個需要被前面位置可達的位置,從最後一個位置開始,last = FINAL,
判斷它的前一個節點pre的可達位置是否包括last位置,如果包括,即pre+nums[pre] >= last的話,就說明該pre節
點可達last,更新last = pre,繼續向後判斷,看後面的節點可否達當前last,依次迴圈遍歷,直到最後判斷last == 0
即最後一個需要可達的位置為初始節點
def canJump_( nums):
if nums == []:
return False
# 初始last是最後一個節點
last = len(nums) - 1
# 這裡其實初始化為len(nums)-2,-1,-1 也是可以的,從倒數第二個節點開始判斷是否可達倒數第一個節點,
#但是從len(nums) - 1, -1, -1雖然冗餘一次但是健壯性更好,譬如len(nums)=1時,1-2 = -1 不好
#雖然提交了也AC了但是顯然不健壯
for i in range(len(nums) - 1, -1, -1):
if i + nums[i] >= last:
last = i
return last == 0