leetcode55 跳躍遊戲

2021-10-03 18:49:17 字數 4631 閱讀 6085

給定乙個非負整數陣列,你最初位於陣列的第乙個位置。陣列中的每個元素代表你在該位置可以跳躍的最大長度。判斷你是否能夠到達最後乙個位置。

示例 1:

輸入: [2,3,1,1,4]

輸出: true

解釋: 我們可以先跳 1 步,從位置 0 到達 位置 1, 然後再從位置 1 跳 3 步到達最後乙個位置。

示例 2:

輸入: [3,2,1,0,4]

輸出: false

解釋: 無論怎樣,你總會到達索引為 3 的位置。但該位置的最大跳躍長度是 0 , 所以你永遠不可能到達最後乙個位置。

本題只需要返回乙個能或不能的結果,並不要求給出路徑,因此也暗示了動態規劃。通常解決並理解乙個動態規劃問題需要以下 步驟:

1.利用遞迴回溯解決問題

2.利用記憶表優化(自頂向下的動態規劃)

3.移除遞迴的部分(自底向上的動態規劃)

回溯法,其實是乙個模板

1, 以當前位置為源流往下摸排所有可以跳到的位置

2, 最終遞迴返回源流位置

3, 然後再以下面乙個位置作為源流位置,重複上述操作

回溯法的效率是很低的,以上已經說過了,本題只需要返回乙個能或不能的結果,並不要求給出路徑,因此回溯法的作用是讓我們理解這個過程,動態規劃法和回溯法的方向是相反的!!

class

solution

:# 回溯法複雜度o(2^n),可以理解成搜尋一顆樹的各個路徑,每個子節點上都有兩條路可以走

defcanjump

(self, nums: list[

int])-

>

bool

:return self.canjumpfromposition(nums,0)

defcanjumpfromposition

(self, nums, position)

:# 邊界

# 當前位置如果為終點,返回true

if position ==

len(nums)-1

:return

true

# 從當前位置能跳到的最遠位置

furtherestjump =

min(nums[position]

+position,

len(nums)-1

)# 從當前位置的下乙個位置開始摸排

for i in

range

(position+

1, furtherestjump+1)

:# 以此為源流往下摸排所有可以跳到的位置

# 最終遞迴返回當前位置,也就是源流

if self.canjumpfromposition(nums, i)

:return

true

# 然後再以下面乙個位置作為源流位置,重複上述操作

# 如果當前位置能跳到的範圍內都檢查過了,都不能到達終點,則說明當前位置不可能到達終點

return

false

自頂向下的動態規劃法,其實就是回溯法,只不過用了記憶表儲存中間結果,依然遞迴所以np難

class

solution

:# 回溯法複雜度o(2^n),可以理解成搜尋一顆樹的各個路徑,每個子節點上都有兩條路可以走

defcanjump

(self, nums: list[

int])-

>

bool

: n =

len(nums)

# 記錄對於每個位置,是否能跳到終點

mem =

[none]*n

mem[n-1]

=true

return self.canjumpfromposition(nums,

0, mem)

defcanjumpfromposition

(self, nums, position, mem)

:# 邊界

# 當前位置如果存在記憶,則直接返回記憶的內容

if mem[position]

!=none

:return mem[position]

# 從當前位置能跳到的最遠位置

furtherestjump =

min(nums[position]

+position,

len(nums)-1

)# 從當前位置的下乙個位置開始摸排,直到它能跳到的最遠位置

for i in

range

(position+

1, furtherestjump+1)

:# 以此為源流往下摸排所有可以跳到的位置

# 最終遞迴返回當前位置,也就是源流

if self.canjumpfromposition(nums, i)

: mem[position]

=true

return

true

# 然後再以下面乙個位置作為源流位置,重複上述操作

# 如果當前位置能跳到的範圍內都檢查過了,都不能到達終點,則說明當前位置不可能到達終點

mem[position]

=false

return

false

真正的動態規劃是和回溯法方向相反的

為了**狀態轉移方程,我們先在上面一種解法的基礎上,簡單反轉一下, o(n2)

值得注意的是,我們發現反轉後,對於每乙個位置,它右邊的位置都是有記憶內容存在的

public class

solution

{def

canjump

(self, nums: list[

int])-

>

bool

: n =

len(nums)

mem =

[none]*n

mem[n-1]

=true

# 從終點左邊一位開始,

for i in

range

(n-2,-

1,-1

):# 當前位置能跳到的最遠位置

furtherestjump =

min(nums[i]

+i, n-1)

# 在當前位置的跳動範圍內遍歷

for j in

range

(i+1

, furtherestjump+1)

:# 如果這個跳動範圍內存在能達終點的位置

if mem[j]

:# 則當前位置也是可以到達終點的

mem[i]

=true

break

# 如果跳動範圍內檢查後,沒有乙個能到終點的位置,則當前位置也無法到終點

mem[i]

=false

return mem[

0]

現在就容易得到我們的狀態轉移方程了,時間複雜度o(n)

class

solution

:# 最右邊的位置一定是可以到達終點的位置,它也是「目前最左邊的乙個可達終點的位置」

# 從終點左邊一位開始往前遍歷每個位置,判斷其是否可以達到「目前最左邊的乙個可達終點的位置」

# 如果可以的話,將這個位置記錄為「目前最左邊的乙個可達終點的位置」

# 狀態轉移方程:

# i + nums[i] >= leftmost: 對於任意位置 i,判斷它是否能到達「目前最左邊的乙個可達終點的位置」leftmost

defcanjump

(self, nums: list[

int])-

>

bool

: leftmost =

len(nums)-1

for i in

range

(leftmost,-1

,-1)

:if i + nums[i]

>= leftmost:

leftmost = i

return leftmost ==

0

作為參考,給出貪心法 o(n)

# 從左邊開始對於每個位置,記錄歷史上能達到的最遠位置,初始為0

defcanjump

(self, nums: list[

int])-

>

bool

: furtherestindex_inhistory =

0 n =

len(nums)

for i in

range

(n):

if i > furtherestindex_inhistory:

return

false

furtherestindex_inhistory =

max(i + nums[i]

, furtherestindex_inhistory)

if furtherestindex_inhistory >= n -1:

return

true

return furtherestindex_inhistory >= n -

1

LeetCode55 跳躍遊戲

leetcode55.跳躍遊戲 給定乙個非負整數陣列,你最初位於陣列的第乙個位置。陣列中的每個元素代表你在該位置可以跳躍的最大長度。判斷你是否能夠到達最後乙個位置。示例 1 輸入 2,3,1,1,4 輸出 true 解釋 從位置 0 到 1 跳 1 步,然後跳 3 步到達最後乙個位置。示例 2 輸入...

LeetCode 55 跳躍遊戲

題目鏈結 題目描述 給定乙個非負整數陣列,你最初位於陣列的第乙個位置。陣列中的每個元素代表你在該位置可以跳躍的最大長度。判斷你是否能夠到達最後乙個位置。示例輸入 2,3,1,1,4 輸出 true 解釋 從位置 0 到 1 跳 1 步,然後跳 3 步到達最後乙個位置。輸入 3,2,1,0,4 輸出 ...

LeetCode 55 跳躍遊戲

問題 給定乙個非負整數陣列,你最初位於陣列的第乙個位置,陣列中的每個元素代表你在該位置可以跳躍的最大長度,判斷你是否能夠到達最後乙個位置。示例 1 輸入 2,3,1,1,4 輸出 true 解釋 從位置 0 到 1 跳 1 步,然後跳 3 步到達最後乙個位置。示例 2 輸入 3,2,1,0,4 輸出...