合縱連橫: 從 路徑搜索 理解DFS背後的本質

小松鼠-avatar-img
發佈於演算法題目解析 個房間
更新 發佈閱讀 18 分鐘


這篇文章,會帶著大家複習以前學過的DFS框架

並且以圖論的應用題與概念為核心,

貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。


DFS 深度優先搜索框架

def dfs( parameter ):

# 邊界條件
if base case or stop condition:

#​ 更新結果
return

# 通則​
for each child node​:

# 更新參數,遞回下一層的節點
dfs( updated parameter)

return


如果特化成圖論中N4 四連通探索的DFS,往往具有下列形式

def dfs( parameter ):

if base case or stop condition:

#​ 更新結果
return

# 更新參數,遞回4連通相鄰的節點
mark current node as visited

# 分別是 左、右、上、下 四個鄰居​
dfs( updated parameter, and go left )
dfs( updated parameter, aad go right )
dfs( updated parameter, and go up )
dfs( updated parameter, and go down )

return

示意圖

vocus|新世代的創作平台

常見的用途:

深度優先探索,探索整張圖(也可以是樹、鏈結串列。)

檢測是否有滿足特定條件的路徑(存在性的判斷)


Word Search - LeetCode 搜尋特定的單字是否存在

這題給定一個矩陣,問我們這個矩陣中,是否存在一條N4 四連通的路徑,路徑上的字串恰好是某個特定的單字。

剛好就是我們剛剛提到的存在性判斷,檢測是否有滿足特定條件的路徑。

掃描整個矩陣,依序從每個格子點出發,依序拜訪四連通鄰居,一直往下走,看看有沒有一條路徑剛好可以拼出某個特定的單字。


實作上有一個細節要特別留意,為了避免重複搜索造成無窮循環,每個被我們拜訪過的格子點會先暫時標記成"#"代表已經走過,所有路徑都拜訪過之後,才會還原回來。


以DFS +N4探索框架的形式實現演算法,程式碼如下:

class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:

if not board:

# Quick response for empty board
return False

h, w = len(board), len(board[0])

# ------------------------------------------------------

def dfs_search(idx: int, x: int, y: int) -> bool:

if x < 0 or x == w or y < 0 or y == h or word[idx] != board[y][x]:
# Reject if out of boundary, or current grid cannot match the character word[idx]
return False

if idx == len(word) - 1:
# Accept when we match all characters of word during DFS
return True

cur = board[y][x]

# mark as '#' to avoid repeated traversal
board[y][x] = '#'

# visit next four neighbor grids
found = dfs_search(idx + 1, x + 1, y) or dfs_search(idx + 1, x - 1, y) or dfs_search(idx + 1, x, y + 1) or dfs_search(idx + 1, x, y - 1)

# recover original grid character after DFS is completed
board[y][x] = cur

return found

# ------------------------------------------------------

return any(dfs_search(0, x, y) for y in range(h) for x in range(w))

接著看進階延伸題,改成找辭典裡面的單字,把有找到的列出來

Word Search II - LeetCode 搜尋給定辭典中的單字

這題多了辭典,我們可以用之前學過前綴樹的技巧,先把辭典建成一顆Trie。

接著,同步在矩陣和Trie裡面搜索每個字元,假如在某一格可以在Trie中找到一個單字,就把這個單字加入到最終結果的清單中


以DFS +N4探索框架的形式實現演算法,程式碼如下:

class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:

# Build a trie from given words
trie = {}
for word in words:
curr = trie
for c in word:
if c not in curr:
curr[c] = {}
curr = curr[c]
curr['@'] = word

H, W = len(board), len(board[0])

res = []
# ===========================================
def dfs(r, c, trie):

# Skip out-of-board search
if not ( 0 <= r < H ) or not ( 0 <= c < W):
return

# Get current character on board
ch = board[r][c]

# Skip if current character does not exist in Trie
if ch not in trie:
return

curr = trie[ch]
word = curr.pop('@', None)
if word:
# We've found a word matched in Trie
res.append(word)

# Avoid repeated traversal
board[r][c] = '#'

dfs(r-1, c, curr)
dfs(r+1, c, curr)
dfs(r, c-1, curr)
dfs(r, c+1, curr)
board[r][c] = ch

# Deleted empty trie branch
if not curr:
trie.pop(ch)

return
# =========================================

# Scan each position on board
for r in range(H):
for c in range(W):
dfs(r, c, trie)

return res

還有一個類似題,要求我們計算可以從起點走到終點,
而且可以拜訪所有空白格子點的路徑方法數

Unique Paths III - LeetCode 拜訪所有空白格子點的路徑方法數

其實也是類似的,我們可以先計算有幾個空白格子點。
接著從起點開始用DFS+N4拜訪整張棋盤,如果走到終點的時候,恰好拜訪過所有空白格子點,就把方法數累加一。最後的路徑方法數總數就是答案。


以DFS +N4探索框架的形式實現演算法,程式碼如下:

# Define grid state to make it more readable

from collections import namedtuple
GridState = namedtuple('GridState', 'start ending empty obstacle')
grid_state = GridState( start = 1, ending = 2, empty = 0, obstacle = -1)


class Solution:
def uniquePathsIII(self, grid):

h, w = len( grid ), len( grid[0] )

available_grid_count = 0
obstacle_count = 0

src_row, src_col = 0, 0

# record for valid path
# a path is valid if and only if it visits all available grid except for obstacles.
self.valid_path_count = 0

for y in range(h) :
for x in range(w):

if grid[y][x] == grid_state.obstacle:
# update counter of obstacle
obstacle_count += 1

elif grid[y][x] == grid_state.start:
# locate start point
src_row, src_col = y, x

# compute counting of all available grids
available_grid_count = h * w - obstacle_count

# ------------------------------------------------------

def dfs( cur_row, cur_col, depth):

if not ( 0 <= cur_row < h) or not ( 0 <= cur_col < w ):
# Skip out-of-board search
return
if grid[cur_row][cur_col] == grid_state.obstacle:

# Terminate DFS when bumping into an obstacle
return

elif grid[cur_row][cur_col] == grid_state.ending:

if depth == available_grid_count:

# If we reach end with visiting all available grids, update valid path count
self.valid_path_count += 1

# Terminate DFS when reach ending
return

else:

state_backup = grid[cur_row][cur_col]

# mark current grid as obstacle to avoid repeated visit
grid[cur_row][cur_col] = grid_state.obstacle

# DFS + N4 to discover each neighbor cell
dfs( cur_row-1, cur_col, depth + 1)
dfs( cur_row+1, cur_col, depth + 1)
dfs( cur_row, cur_col-1, depth + 1)
dfs( cur_row, cur_col+1, depth + 1)

# restore original grid state
grid[cur_row][cur_col] = state_backup

return

# ------------------------------------------------------

dfs(src_row, src_col, depth = 1)
return self.valid_path_count


結語

好,今天一口氣介紹了最精華的部分,

通用的DFS+N4探索框架,還有相關的路徑應用題與演算法建造,


希望能幫助讀者、觀眾徹底理解它的原理,

並且能夠舉一反三,洞察其背後的本質和了解相關的應用領域!


感謝收看囉! 我們下篇文章再見~

留言
avatar-img
小松鼠的演算法樂園
99會員
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
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
Thumbnail
這篇文章,會帶著大家複習以前學過的格子點DP框架, 並且以移動路徑Unique Path的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 格子點DP框架 依循題目的定義和規則,找出格子點移動的共同模式。 以本篇文章的例題為例,每一步可以選擇往右走一個
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架 結合樹型DP, 並且以路徑和Path Sum的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): if base case or sto
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架 結合樹型DP, 並且以路徑和Path Sum的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): if base case or sto
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 直線排列Permutations 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所有可能的情況,遞迴展開所有分
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
Thumbnail
這篇文章,會帶大家快速回顧DFS+回溯法框架(還沒看過或想複習的可以點連結進去)。 用DFS+回溯法框架,解開 組合數之和 Combination Sum 的全系列題目。 幫助讀者鞏固DFS+回溯法框架這個重要的知識點。 回顧 DFS+回溯法框架 白話的意思 # 列舉所以可能的情況,
Thumbnail
這篇文章,會帶著大家複習以前學過的區間DP框架, 並且以區間DP的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 基本的區間DP框架(限制條件: 相鄰的兩項不允許同時選擇) 在House Robbery這題中,我們學會了一種基本的區間DP框架。
Thumbnail
這篇文章,會帶著大家複習以前學過的區間DP框架, 並且以區間DP的概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個實用的演算法框架。 基本的區間DP框架(限制條件: 相鄰的兩項不允許同時選擇) 在House Robbery這題中,我們學會了一種基本的區間DP框架。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
Thumbnail
這篇文章,會帶著大家複習以前學過的DFS框架, 並且以圖論的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 DFS 深度優先搜索框架 def dfs( parameter ): # 邊界條件 if base case or stop cond
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News