最短路徑應用: 遊戲模擬 Jump Game IV 青蛙過河 IV_Leetcode_#1345

更新 發佈閱讀 8 分鐘

題目敘述

題目會給我們一個輸入陣列arr,起始點固定在索引為0的位置,
終點固定在索引為n-1的位置

假設當下所在的索引位置為i,那麼每次移動的時候,可以跳到i-1i+1,或者其他和我有相同元素值的位置arr[j], where arr[j] = arr[i]。

例如:

假設當下在i=3的位置,arr[i] = 5,那麼下一步可以跳到i-1=2 或者i+1=4,或者陣列上其他陣列元素值=5的位置。


請問,從起點0出發跳到終點n-1,所需要的最小跳躍次數為多少?


題目的原文敘述


測試範例

Example 1:

Input: arr = [100,-23,-23,404,100,23,23,23,3,404]
Output: 3
Explanation: You need three jumps from index 0 --> 4 --> 3 --> 9. Note that index 9 is the last index of the array.

arr[0] 跳到 arr[4],因為兩者的元素值相同,都是100
arr[4] 跳到 arr[3]3 = 4-1 是相差一隔的鄰居​
arr[3] 跳到 arr[9],因為兩者的元素值相同,都是404

Example 2:

Input: arr = [7]
Output: 0
Explanation: Start index is the last index. You do not need to jump.

起點剛好等於終點,不用跳就已經抵達終點。
所以0次。​

Example 3:

Input: arr = [7,6,9,6,9,6,9,7]
Output: 1
Explanation: You can jump directly from index 0 to index 7 which is last index of the array.

arr[0] 可以直接跳到 arr[7],因為兩者的元素值相同,都是7

約束條件

Constraints:

  • 1 <= arr.length <= 5 * 10^4

陣列長度界於1~五萬之間。

  • -10^8 <= arr[i] <= 10^8

每個陣列元素值界於 負一億~正一億 之間。


演算法

題目已經無形中保證一定有解,為什麼?

因為最差情況下,就是每次都從i往右跳一格到i+1,總有一步會抵達終點n-1。

但是,題目要問的是從起點0到終點n-1的最短路徑需要幾次跳躍?


抽象的想,可以把arr[i]每個陣列格子都視為一個節點

然後 arr[i] 和 arr[i-1], arr[i+1]各有一條邊相連成本為1

假如arr[j] = arr[i] 元素值相等,arr[i] 也和其他的arr[j] 有邊相連成本為1


到這裡,就把原本跳躍次數的問題,轉化成圖論中的最短路徑搜索問題
起點為Node 0,終點為 n-1,最少要經過幾條邊(相當於幾次跳躍)才能抵達。


無權重的圖 或者 權重都相等的圖中尋找最短路徑,那很自然就會想到BFS先天具有點播源擴散的特質,也因此具有最短路徑的搜索性質


我們只要從Node 0 開始進行BFS廣度優先搜尋,一層一層往外拜訪,
當拜訪到Node n-1的時候,
當下的步數 = 最短路徑長度 = 從起點到終點的最小跳躍次數


程式碼 BFS先天在無權圖 或者 等權圖 具有最短路徑的特質

class Solution:
def minJumps(self, arr):

n = len(arr)
destination = n-1

## Dictionary: a group of the same number
# key: number
# value: idx of number
same_number = defaultdict(list)

for idx, number in enumerate(arr):
same_number[number].append(idx)

# src = 0, step = 0
bfs_q = deque([(0, 0)])

# visited set
seen = set([0])

# Launch BFS from starting index = 0
# BFS naturaly has shortest path from source to destination.
while bfs_q:

cur, step = bfs_q.popleft()

# Reach destination
if cur == destination:
return step

# Go to the neighbor to previous index as well as next index
for next_idx in (cur+1, cur-1):
if 0 <= next_idx < n and next_idx not in seen:
bfs_q.append( (next_idx, step+1) )
seen.add( next_idx )

# Go to friend index who has the same number with me
for next_idx in same_number[ arr[cur] ]:
if next_idx not in seen:
bfs_q.append( (next_idx, step+1) )
seen.add( next_idx )

# Avoid repeated redundant traversal which would not yield better result
del same_number[ arr[cur] ]


return -1

複雜度分析 BFS先天在無權圖 或者 等權圖 具有最短路徑的特質

令n=輸入陣列nums的長度 = 圖中的節點總數

時間複雜度:

從start拜訪整張圖,每個節點至多訪問一次,每個節點至少有兩條向外的指向邊。

最後一定能找到最短路徑(因為最差情況就是每次都往右走,總有一步會走到終點)。

拜訪整張圖所需時間為O(n)。


空間複雜度:

起點開始BFS逐層搜索每一層拜訪彼此相差一步的節點,最大長度為O(n)。


關鍵知識點

無權重的圖 或者 權重都相等的圖中尋找最短路徑,那很自然就會想到BFS先天具有點播源擴散的特質,也因此具有最短路徑的搜索性質


我們只要從Node 0 開始進行BFS廣度優先搜尋,一層一層往外拜訪,

當拜訪到Node n-1的時候,

當下的步數 = 最短路徑長度 = 從起點到終點的最小跳躍次數


這邊也整理了一些常用的BFS、DFS圖論中的應用場景,提供讀者作為參考。


Reference:

[1] Jump Game IV_Python O(n) by BFS with natural shortest path itself [w/ Comment]

留言
avatar-img
小松鼠的演算法樂園
98會員
428內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/09/26
Leetcode 729. My Calendar I 給定一個行事曆的class定義和行程安排的介面interface。 請完成下列function 1.建構子MyCalendar() 初始化MyCalendar物件 2.boolean book(int start, int end) 插入新行程
Thumbnail
2024/09/26
Leetcode 729. My Calendar I 給定一個行事曆的class定義和行程安排的介面interface。 請完成下列function 1.建構子MyCalendar() 初始化MyCalendar物件 2.boolean book(int start, int end) 插入新行程
Thumbnail
2024/09/10
Insert Greatest Common Divisors in Linked List 題目給定一個鏈結串列, 請在兩兩節點之間加入一個新節點,新節點的值為兩者之間的最大公因數。 最後返回新串列的head node作為答案。
Thumbnail
2024/09/10
Insert Greatest Common Divisors in Linked List 題目給定一個鏈結串列, 請在兩兩節點之間加入一個新節點,新節點的值為兩者之間的最大公因數。 最後返回新串列的head node作為答案。
Thumbnail
2024/09/09
2326. Spiral Matrix IV 題目給定一個Linked list和對應的矩陣高度m、寬度n。 請依照順時針的拜訪順序, 從左上角出發,依照次序把Linked List的內容填到矩陣裡。 如果有剩餘不足的空位,就填補-1。 最後將填補好的矩陣返回作為答案。
Thumbnail
2024/09/09
2326. Spiral Matrix IV 題目給定一個Linked list和對應的矩陣高度m、寬度n。 請依照順時針的拜訪順序, 從左上角出發,依照次序把Linked List的內容填到矩陣裡。 如果有剩餘不足的空位,就填補-1。 最後將填補好的矩陣返回作為答案。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目敘述 Combination Sum IV 給定一個輸入陣列nums,和目標值target,從nums裡面挑數字去湊出總和 = target,數字可以重複挑選。 請問有多少排列數可以湊出target? 註: 排列數的意思就是位置不同代表兩種不同的方法數。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目會給定一個陣列nums和一個目標值goal。計算子陣列總和=goal的數目有多少。演算法包含前綴和和字典的技巧,時間複雜度為O(n),空間複雜度為O(n)。
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目會給定我們一個整數陣列nums,要求我們把裡面的0做元素交換,把0都搬到陣列的右邊。題目要求必須in-place在原本的陣列裡面做操作,不可以額外建立新的陣列。 題目的原文敘述 測試範例 Example 1: Input: nums = [0,1,0,3,12] Outpu
Thumbnail
題目敘述 題目給定我們一個輸入陣列nums 要求我們以正、負交叉排列的方式重組陣列,並且必須保持原本的相對順序。 並且以陣列的形式輸出返回答案。 例[5, 1, -2, -3] 重排後為 [5, -2, 1, -3] 題目的原文敘述 測試範例 Example 1: Input:
Thumbnail
題目敘述 題目給定我們一個輸入陣列nums 要求我們以正、負交叉排列的方式重組陣列,並且必須保持原本的相對順序。 並且以陣列的形式輸出返回答案。 例[5, 1, -2, -3] 重排後為 [5, -2, 1, -3] 題目的原文敘述 測試範例 Example 1: Input:
Thumbnail
題目敘述 題目會給我們一個輸入陣列arr,起始點固定在索引為0的位置, 終點固定在索引為n-1的位置。 假設當下所在的索引位置為i,那麼每次移動的時候,可以跳到i-1,i+1,或者其他和我有相同元素值的位置arr[j], where arr[j] = arr[i]。 例如: 假設當下在i=3
Thumbnail
題目敘述 題目會給我們一個輸入陣列arr,起始點固定在索引為0的位置, 終點固定在索引為n-1的位置。 假設當下所在的索引位置為i,那麼每次移動的時候,可以跳到i-1,i+1,或者其他和我有相同元素值的位置arr[j], where arr[j] = arr[i]。 例如: 假設當下在i=3
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以左右位移的固定長度。 例如,假設 nums[i] = 3,那麼下一步可以移動到nums[i-3] 或 nums[i+3]這兩個格子點。 題目​會給定一個起始點start索引位置,請問我們能不能走到內部數值為0的格子點?
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以左右位移的固定長度。 例如,假設 nums[i] = 3,那麼下一步可以移動到nums[i-3] 或 nums[i+3]這兩個格子點。 題目​會給定一個起始點start索引位置,請問我們能不能走到內部數值為0的格子點?
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 題目保證始從最左邊的格子點出發開始跳,一定可以成功抵達終點,請問最少跳躍次數是說少? 題目的原文敘述 測試範例 Example 1: Input: nums = [2,3,1,1,4] Outp
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 題目保證始從最左邊的格子點出發開始跳,一定可以成功抵達終點,請問最少跳躍次數是說少? 題目的原文敘述 測試範例 Example 1: Input: nums = [2,3,1,1,4] Outp
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 一開始從最左邊的格子點出發開始跳,請問可以成功抵達終點,也就是最右邊的格子點嗎? 如果可以,返回 True。 如果不行,返回False。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 一開始從最左邊的格子點出發開始跳,請問可以成功抵達終點,也就是最右邊的格子點嗎? 如果可以,返回 True。 如果不行,返回False。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目敘述 題目會給定一個整數陣列arr,要求我們判斷是否每個元素的出現次數都不同? 題目的原文敘述 測試範例 Example 1: Input: arr = [1,2,2,1,1,3] Output: true Explanation: The value 1 has 3 occurre
Thumbnail
題目敘述 題目會給定一個整數陣列arr,要求我們判斷是否每個元素的出現次數都不同? 題目的原文敘述 測試範例 Example 1: Input: arr = [1,2,2,1,1,3] Output: true Explanation: The value 1 has 3 occurre
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News