LeetCode -- 1970. Last Day Where You Can Still Cross

更新 發佈閱讀 7 分鐘

核心概念

使用二分搜搭配 BFS。

利用二分搜天數,找到 "The last day where we can still cross"。當二分搜到的該天還有路可以走則繼續往後面的天數二分搜,若沒路可以走則往前面的天數二分搜。

舉個例子,假如是 3*3 的矩陣,會有九天需要確認。第一次檢查第五天是否有路可以走,如果有,則檢查第七或第八天 (取決於程式碼如何設計);如果沒有,則檢查第二或第三天 (取決於程式碼如何設計)

BFS 則是負責遍歷所有路徑。仔細來說就是,每一層迴圈都去查找一個 raw 中各元素的上下左右是否可以走 (檢查上方是因為可能可以往上繞)。

當然,其中還有一些小細節。例如,最基礎的邊界檢查;用 set 儲存走過的格子 (如果使用 Python),因為若 (1,1) (1,2) (1,3) 可走,(1,2) 會在檢查 (1,1) 右邊,(1,2)左邊後被新增兩次。至於用 set 是因為,set 在 Python 中是以 hashtable 形式建立,查詢是否重複時比較快;以及用遞迴實作 BFS 可能會 MLE。

程式碼執行流程

在 Solution class 中開另一個 canCross 函數處理 BFS。

在 latestDayToCross 函數中,變數 left, right 儲存二分搜的左界和右界。

執行 while 迴圈直到 left > right 或 left == right。接著,將中間值 (要檢查的天) 帶入 canCross 函數。如果回傳 True,則 left = mid + 1;如果回傳 False,則 right = mid。舉個例子,現在有 1, 2, 3, 4 天。其中,1 和 2 可以走,3 和 4 不行走。第一次 left = 1, right = 4, mid = 2;第二次 left = 3, right = 4, mid = 3 ; 第三次 left = 3, right = 3 結束。最後,回傳 right -1。減一是因為找到的那天是不能走的。

canCross 中,我們先將 cells 轉成 set 型態方便之後檢查。

變數 queue 用來儲存當前的位置,當要檢查格子時從左邊 pop 出來,達到先進先出(右進左出);visited 用來儲存走過的格子避免重複檢查。

對於矩陣的第一層,我們獨立檢察。如果不在 water 中,就新增進 queue 和 visited 中。至於為什麼用 tuple 來儲存 r 和 c,是因為 tuple is hashable,換句話說,只有 tuple 可以新增進 set,其餘的像 list、dictionary 都不行。可能有人會看到除 add 還有一個 update 函式也可以新增資料,並且還可以將 list 當參數帶入,但新增進 set 的資料不會兩兩一對。

raw-image

這裡,我們舉個例子

raw-image

假如我們有一個 3*3 的矩陣,並且還在第一天的狀態。此時,當我們的程式碼檢查完第一層矩陣後 queue = [(0,0), (0,2)], visited = [(0,0), (0,2)]

接著往下走是 BFS 的 while 迴圈。這裡,我們執行到 queue 沒有東西為止

我們從 queue 中的最左邊開始取,並用 r 和 c 來存。如果 r == row - 1,代表我們已經到最後一個 row,檢查完畢,這天還是有路可以走的,回傳 True。如果還沒走到最後,則去檢查剛剛取出那點的上下左右是否可以走

以下是完整的程式碼

from collections import deque

class Solution:
    def canCross(self, day: int, row: int, col: int, cells: list) -> bool:
        # 建立第 day 天的水域
        water = set()
        for i in range(day):
            water.add((cells[i][0]-1, cells[i][1]-1))
        # BFS
        queue = deque()
        visited = set()
        for c in range(col):
            if (0, c) not in water:
                queue.append((0, c))
                visited.add((0, c))
        while queue:
            r, c = queue.popleft()
            if r == row - 1:
                return True
            for dr, dc in [(1,0), (-1,0), (0,1), (0,-1)]:
                nr, nc = r + dr, c + dc
                if (0 <= nr < row and 0 <= nc < col
                    and (nr, nc) not in water
                    and (nr, nc) not in visited):
                    visited.add((nr, nc))
                    queue.append((nr, nc))
        return False

    def latestDayToCross(self, row: int, col: int, cells: list) -> int:
        left, right = 1, (row*(col-1))+1
        while left < right and left != right:
            mid = (left + right ) // 2
            if self.canCross(mid, row, col, cells):
                left = mid + 1 # 還能走,試更晚的天數
            else:
                right = mid # 走不通,試更早的天數
        return left-1



留言
avatar-img
周濡墨的沙龍
19會員
121內容數
有別於未付費的文章,專題區的文章偏向愛情短篇小說,較有戲劇性,篇幅也會較長;未付費文章會偏向極短篇小說,並且以類似散文的手法寫作
周濡墨的沙龍的其他內容
2025/09/01
Description Given an m x n binary matrix mat, return the number of submatrices that have all ones. 給定一個 m x n 二進位矩陣 mat ,傳回全為 1 的子矩陣的數量。 Solution
Thumbnail
2025/09/01
Description Given an m x n binary matrix mat, return the number of submatrices that have all ones. 給定一個 m x n 二進位矩陣 mat ,傳回全為 1 的子矩陣的數量。 Solution
Thumbnail
2025/08/19
Description You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of thei
Thumbnail
2025/08/19
Description You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of thei
Thumbnail
2025/08/19
前言 為了完成 LeetCode 題目 2. Add Two Numbers,我特地學習了 Python 中的 Linked List。不過我花了大約一小時的時間翻閱中英文影片及文章,卻始終找不到滿意的解說。 於是,我請 AI 當我的老師,生成了一篇 Python Linked List 教學。
2025/08/19
前言 為了完成 LeetCode 題目 2. Add Two Numbers,我特地學習了 Python 中的 Linked List。不過我花了大約一小時的時間翻閱中英文影片及文章,卻始終找不到滿意的解說。 於是,我請 AI 當我的老師,生成了一篇 Python Linked List 教學。
看更多
你可能也想看
Thumbnail
public class MultiplicationTable { public static void main(String[] args) { int size = 9; // 設定九九乘法表的大小 // 雙層迴圈用於生成九九乘法表 f
Thumbnail
public class MultiplicationTable { public static void main(String[] args) { int size = 9; // 設定九九乘法表的大小 // 雙層迴圈用於生成九九乘法表 f
Thumbnail
我今天學到了一個應用程式,只要把自己想打得字打進去打進去,在設定自己喜歡的圖片,他就換幫你轉換成一種密密麻麻很酷的風格。這堂課讓我學到很多東西,也明白現在的科技做的事越來越多了~希望自己以後能更努力的學習
Thumbnail
我今天學到了一個應用程式,只要把自己想打得字打進去打進去,在設定自己喜歡的圖片,他就換幫你轉換成一種密密麻麻很酷的風格。這堂課讓我學到很多東西,也明白現在的科技做的事越來越多了~希望自己以後能更努力的學習
Thumbnail
寫程式是一件讓人感到害怕的一件事,但是寫程式真的對職場幫助很大,不管是邏輯思考或是資料處理,都讓我跟不會寫程式的人高度不一樣......
Thumbnail
寫程式是一件讓人感到害怕的一件事,但是寫程式真的對職場幫助很大,不管是邏輯思考或是資料處理,都讓我跟不會寫程式的人高度不一樣......
Thumbnail
無論年紀多大多小,只要「願意」付出行動 時間、地點都不是問題 現在都有兒童程式課程 小朋友學的是利用積木組合而成的程式 大朋友就可以直接拿鍵盤來劈哩啪啦開始寫程式碼囉~
Thumbnail
無論年紀多大多小,只要「願意」付出行動 時間、地點都不是問題 現在都有兒童程式課程 小朋友學的是利用積木組合而成的程式 大朋友就可以直接拿鍵盤來劈哩啪啦開始寫程式碼囉~
Thumbnail
為什麼要學習程式呢? 程式是怎麼分類的? 能處理什麼事情?
Thumbnail
為什麼要學習程式呢? 程式是怎麼分類的? 能處理什麼事情?
Thumbnail
白晝的餘燼用酒澆熄 自愛情燃燒後 一壺傾倒的月光    漫過你的唇    輕吻沉醉的靈魂 這是你的城市 不是我的  我的城市在夜裡燃燒 自你走後 漫天紛飛的細雨                                                                  
Thumbnail
白晝的餘燼用酒澆熄 自愛情燃燒後 一壺傾倒的月光    漫過你的唇    輕吻沉醉的靈魂 這是你的城市 不是我的  我的城市在夜裡燃燒 自你走後 漫天紛飛的細雨                                                                  
Thumbnail
原本這次的徵文題目應該是「整座城市都在閱讀─我讀2021台北國際書展」,最後很可惜這個題目也被迫夭折。 不過實體無法做到的,就以數位實現,這本來就是方格子一直在做的事。所以即使書展取消了,閱讀也不曾/不該/不會停止。邀請格友們來分享你最近的購書清單…
Thumbnail
原本這次的徵文題目應該是「整座城市都在閱讀─我讀2021台北國際書展」,最後很可惜這個題目也被迫夭折。 不過實體無法做到的,就以數位實現,這本來就是方格子一直在做的事。所以即使書展取消了,閱讀也不曾/不該/不會停止。邀請格友們來分享你最近的購書清單…
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News