優先搜索(DFS)實戰

目錄

一、DFS通用解題思路?

二、逐題拆解?

三、四題對比

四、總結:DFS解決矩陣問題的“萬能模板”?


在算法解題中,矩陣連通性問題是高頻考點,而深度優先搜索(DFS)是解決這類問題的核心工具之一。它通過“一條路走到底,不通再回頭”的思路,能高效遍歷矩陣中相鄰的元素,進而完成標記、計數或替換等操作。本文將結合 LeetCode 130.被圍繞的區域、695.島嶼的最大面積、200.島嶼數量 和 733.圖像渲染 四題,拆解DFS在矩陣問題中的通用解題框架,并對比各題的差異點,幫助大家舉一反三。
?


一、DFS通用解題思路
?


矩陣問題的核心是“相鄰元素”的處理(通常指上下左右四個方向,特殊情況會包含對角線),DFS的作用就是從一個起始點出發,遍歷所有與起始點連通的元素,并執行特定操作(如標記、修改值)。其通用步驟可歸納為:
?
1.?邊界判斷:遍歷矩陣時,先檢查當前元素是否越界(行號<0或>=矩陣行數,列號<0或>=矩陣列

數),若越界則直接返回,避免程序報錯。
?

2.?條件篩選:判斷當前元素是否符合“可遍歷”條件(如是否為目標值、是否已被標記),若不符合

則返回,減少無效遍歷。
?

3.?執行操作:對符合條件的當前元素執行操作(如標記為已訪問、修改數值),防止后續重復遍

歷。
?

4.?遞歸遍歷:分別向當前元素的上、下、左、右四個方向遞歸調用DFS,繼續遍歷連通元素。
?
這四題均圍繞該框架展開,差異僅在于“條件篩選”和“執行操作”的具體內容,接下來我們逐題分析。
?


二、逐題拆解
?


1. LeetCode 130.被圍繞的區域——“邊界連通元素的保護”
?
題目核心需求
?
給定一個 ?m x n??的矩陣,將所有被 ?'X'??圍繞的 ?'O'??替換為 ?'X'?,與矩陣邊界直接或間接連通的 ?'O'??需保留。
?
解題關鍵
?
被圍繞的 ?'O'??的本質是“不與邊界連通”,因此我們可以先標記出所有與邊界連通的 ?'O'?,再將未被標記的 ?'O'??替換為 ?'X'?,最后還原被標記的 ?'O'?。
?
DFS實現步驟
?
1.?邊界遍歷:先遍歷矩陣的四條邊界(第一行、最后一行、第一列、最后一列),若遇到 ?'O'?,則以該元素為起點執行DFS。
2.?DFS標記:在DFS中,將與邊界連通的 ?'O'??標記為臨時符號(如 ?'*'?),避免后續被誤替換。
3.?矩陣更新:遍歷整個矩陣,將剩余的 ?'O'?(未與邊界連通,即被圍繞的)替換為 ?'X'?,將 ?'*'??還原為 ?'O'?。

?
關鍵代碼片段

// DFS:標記與邊界連通的'O'為'*'
void dfs(int x, int y, vector<vector<char>>& board) {// 1.邊界判斷 + 2.條件篩選(非'O'則返回)if (x < 0 || x >= board.size() || y < 0 || y >= board[0].size() || board[x][y] != 'O') {return;}// 3.執行操作:標記為'*'board[x][y] = '*';// 4.遞歸遍歷四個方向dfs(x + 1, y, board);dfs(x - 1, y, board);dfs(x, y + 1, board);dfs(x, y - 1, board);
}void solve(vector<vector<char>>& board) {if (board.empty()) return;int m = board.size(), n = board[0].size();// 遍歷邊界,標記連通的'O'for (int i = 0; i < n; i++) {if (board[0][i] == 'O') dfs(0, i, board); ? ? ? // 第一行if (board[m-1][i] == 'O') dfs(m-1, i, board); ? // 最后一行}for (int i = 0; i < m; i++) {if (board[i][0] == 'O') dfs(i, 0, board); ? ? ? // 第一列if (board[i][n-1] == 'O') dfs(i, n-1, board); ? // 最后一列}// 更新矩陣for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (board[i][j] == 'O') board[i][j] = 'X'; ?// 未標記的'O'替換為'X'if (board[i][j] == '*') board[i][j] = 'O'; ?// 標記的'*'還原為'O'}}
}

2. LeetCode 200.島嶼數量——“連通區域的計數”
?
題目核心需求
?
給定一個 ?m x n??的二進制矩陣,?'1'??代表陸地,?'0'??代表水域,計算矩陣中島嶼的數量(島嶼是由相鄰的 ?'1'??組成的連通區域,相鄰指上下左右)。
?
解題關鍵
?
每遇到一個未被訪問的 ?'1'?,就通過DFS遍歷其所有連通的 ?'1'??并標記為已訪問,每完成一次這樣的DFS,島嶼數量加1。
?

DFS實現步驟
?
1.?矩陣遍歷:遍歷矩陣中的每個元素,若遇到 ?'1'??且未被標記,則島嶼數量加1,并執行DFS。
2.?DFS標記:在DFS中,將當前的 ?'1'??標記為 ?'0'?(或其他符號),表示已訪問,避免重復計數。
3.?遞歸遍歷:向四個方向遞歸,將連通的 ?'1'??全部標記為 ?'0'?。
?

關鍵代碼片段
?
?

void dfs(int x, int y, vector<vector<char>>& grid) {// 1.邊界判斷 + 2.條件篩選(非'1'則返回)if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] != '1') {return;}// 3.執行操作:標記為'0'(已訪問)grid[x][y] = '0';// 4.遞歸遍歷四個方向dfs(x + 1, y, grid);dfs(x - 1, y, grid);dfs(x, y + 1, grid);dfs(x, y - 1, grid);
}int numIslands(vector<vector<char>>& grid) {if (grid.empty()) return 0;int m = grid.size(), n = grid[0].size();int count = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == '1') { ?// 遇到未訪問的陸地count++;dfs(i, j, grid); ? ? ?// 標記整個島嶼}}}return count;
}

3. LeetCode 695.島嶼的最大面積——“連通區域的最大尺寸”
?
題目核心需求
?
給定一個 ?m x n??的二進制矩陣,?1??代表陸地,?0??代表水域,計算矩陣中最大島嶼的面積(島嶼面積為連通的 ?1??的個數)。
?
解題關鍵
?
與“島嶼數量”類似,但DFS需額外統計每個島嶼的面積(即連通的 ?1??的個數),并實時更新最大值。

?
DFS實現步驟
?
1.?矩陣遍歷:遍歷每個元素,若遇到 ?1??且未被標記,執行DFS并計算該島嶼的面積。
2.?DFS計數:在DFS中,將當前 ?1??標記為 ?0?(已訪問),并返回“1 + 四個方向連通區域的面積之和”,即當前島嶼的總面積。
3.?更新最大值:每次計算出一個島嶼的面積后,與當前最大值比較,保留較大值。

?
關鍵代碼片段

int dfs(int x, int y, vector<vector<int>>& grid) {// 1.邊界判斷 + 2.條件篩選(非1則返回0,無面積)if (x < 0 || x >= grid.size() || y < 0 || y >= grid[0].size() || grid[x][y] != 1) {return 0;}// 3.執行操作:標記為0(已訪問)grid[x][y] = 0;// 4.遞歸遍歷四個方向,累加面積return 1 + dfs(x+1, y, grid) + dfs(x-1, y, grid) + dfs(x, y+1, grid) + dfs(x, y-1, grid);
}int maxAreaOfIsland(vector<vector<int>>& grid) {if (grid.empty()) return 0;int m = grid.size(), n = grid[0].size();int maxArea = 0;for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (grid[i][j] == 1) {int area = dfs(i, j, grid); ?// 計算當前島嶼面積maxArea = max(maxArea, area); // 更新最大值}}}return maxArea;
}

4. LeetCode 733.圖像渲染——“指定區域的顏色替換”
?
題目核心需求
?
給定一個 ?m x n??的圖像(由整數表示顏色),以及一個起始坐標 ?(sr, sc)??和新顏色 ?newColor?,將起始坐標所在的“連通區域”(顏色與起始坐標原顏色相同,相鄰指上下左右)全部替換為新顏色。
?
解題關鍵
?
若起始坐標的原顏色與新顏色相同,直接返回圖像(避免無限遞歸);否則通過DFS遍歷所有連通的原顏色像素,替換為新顏色。
?
DFS實現步驟
?
1.?初始判斷:記錄起始坐標的原顏色 ?oldColor?,若 ?oldColor == newColor?,直接返回圖像。
2.?DFS替換:在DFS中,將當前像素的顏色替換為 ?newColor?,并向四個方向遞歸,僅替換顏色為 ?oldColor??的像素。

?
關鍵代碼片段

void dfs(int x, int y, int oldColor, int newColor, vector<vector<int>>& image) {// 1.邊界判斷 + 2.條件篩選(非oldColor則返回)if (x < 0 || x >= image.size() || y < 0 || y >= image[0].size() || image[x][y] != oldColor) {return;}// 3.執行操作:替換為新顏色image[x][y] = newColor;// 4.遞歸遍歷四個方向dfs(x+1, y, oldColor, newColor, image);dfs(x-1, y, oldColor, newColor, image);dfs(x, y+1, oldColor, newColor, image);dfs(x, y-1, oldColor, newColor, image);
}vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {int oldColor = image[sr][sc];if (oldColor == newColor) return image; // 避免無限遞歸dfs(sr, sc, oldColor, newColor, image);return image;
}

三、四題對比

題目核心操作??條件篩選(DFS終止條件)特殊處理?
130.被圍繞的區域標記邊界連通的'O'非'O'或越界需還原標記(*→O)、替換未標記(O→X)
200.島嶼數量標記陸地并計數非'1'或越界每啟動一次DFS,島嶼數+1?
695.最大島嶼面積標記陸地并計算面積非1或越界DFS返回面積,實時更新最大值?
733.圖像渲染替換連通區域的顏色非原顏色或越界,原顏色==新顏色直接返回直接替換為新顏色,無需還原?

?

四、總結:DFS解決矩陣問題的“萬能模板”
?

通過以上四題的分析,我們可以提煉出一個“矩陣DFS萬能模板”,只需根據題目需求修改?條件篩選?和?執行操作?即可:

// 通用DFS函數:x,y為當前坐標,其他參數根據題目需求補充(如矩陣、目標值、新值等)
void dfs(int x, int y, 額外參數) {// 1. 邊界判斷if (x < 0 || x >= 矩陣行數 || y < 0 || y >= 矩陣列數) {return;}// 2. 條件篩選(是否為目標元素、是否已訪問等)if (矩陣[x][y] 不滿足條件) {return;}// 3. 執行操作(標記、修改值、計數等)對矩陣[x][y]執行具體操作;// 4. 遞歸遍歷四個方向dfs(x + 1, y, 額外參數);dfs(x - 1, y, 額外參數);dfs(x, y + 1, 額外參數);dfs(x, y - 1, 額外參數);
}// 主函數:遍歷矩陣,觸發DFS
void mainFunction(矩陣類型& 矩陣, 其他參數) {if (矩陣為空) return;int 矩陣行數 = 矩陣.size(), 矩陣列數 = 矩陣[0].size();for (int i = 0; i < 矩陣行數; i++) {for (int j = 0; j < 矩陣列數; j++) {if (觸發DFS的條件) { // 如遇到未訪問的目標元素dfs(i, j, 額外參數);}}}// 若需后續處理(如還原標記、返回結果),在此處執行
}

矩陣連通性問題的本質是“找到并處理符合條件的連通區域”,DFS通過遞歸高效實現了這一過程。掌握上述模板后,無論題目要求是標記、計數還是替換,都能快速適配,真正做到“一題通,題題通”。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96075.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96075.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96075.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

門控MLP(Qwen3MLP)與稀疏混合專家(Qwen3MoeSparseMoeBlock)模塊解析

Qwen3MLP Qwen3MLP是基于門控機制的MLP模塊&#xff0c;采用了類似門控線性單元&#xff08;GLU&#xff09;的結構。它通過三個線性變換層&#xff08;gate_proj、up_proj和down_proj&#xff09;和SiLU激活函數&#xff0c;先將輸入從隱藏維度擴展到中間維度&#xff0c;經過…

產線相機問題分析思路

現象&#xff1a;復現問題 原因&#xff1a;問題分析、溯源&#xff0c;定位根本原因&#xff1b; 方案&#xff1a;提出解決方案、規避措施 驗證&#xff1a;導入、驗證方案是否可行&#xff08;先小批量、再大批量&#xff09;&#xff1b;一. 現象產線反饋4pcs預覽又臟污、劃…

【開關電源篇】EMI輸入電路-超簡單解讀

1. 輸入電路主要包含哪些元件&#xff1f;濾波設計需遵循什么原則&#xff1f; 輸入電路是電子設備&#xff08;如開關電源&#xff09;的“入口”&#xff0c;核心作用是抑制電磁干擾&#xff08;EMI&#xff09;、保護后級電路&#xff0c;其設計直接影響設備的穩定性和電磁…

勝券POS:打造智能移動終端,讓零售智慧運營觸手可及

零售企業運營中依然存在重重挑戰&#xff1a;收銀臺前的長隊消磨著顧客的耐心&#xff0c;倉庫里的庫存盤點不斷侵蝕著員工的精力&#xff0c;導購培訓的成本長期居高不下卻收效甚微……面對這些痛點&#xff0c;零售企業或許都在等待一個破局的答案。百勝軟件勝券POS&#xff…

(回溯/組合)Leetcode77組合+39組合總和+216組合總和III

為什么不能暴力&#xff0c;因為不知道要循環多少次&#xff0c;如果長度為n&#xff0c;難道要循環n次么&#xff0c;回溯的本質還是暴力&#xff0c;但是是可以知道多少層的暴力 之所以要pop是因為回溯相當于一個樹形結構&#xff0c;要pop進行第二個分支 剪枝&#xff1a;…

07 下載配置很完善的yum軟件源

文章目錄前言ping 測試網絡排查原因排查虛擬機的虛擬網絡是否開啟檢查net8虛擬網絡和Centos 7的ip地址是否在一個局域網點擊虛擬網絡編輯器點擊更改設置記錄net8的虛擬網絡地址ip a記錄Centos 7的ip地址比較net8和Centos 7的ip地址是否在一個網段解決問題問題解決辦法修改net8的…

SpringBoot中添加健康檢查服務

問題 今天需要給一個Spring工程添加健康檢查。 pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency>application.yml management:endpoints:web:e…

AI工具深度測評與選型指南 - AI工具測評框架及方法論

目錄引言&#xff1a;AI工具爆發期的機遇與挑戰一、從AI模型到AI工具&#xff1a;核心認知與生態解析1.1 DeepSeek&#xff1a;快速出圈的國產大模型代表1.2 大模型的核心能力與類型劃分1.2.1 大模型的三層能力與“雙系統”類比1.2.2 生成模型與推理模型的核心差異1.3 AI工具與…

Spring Cloud Alibaba快速入門02-Nacos(中)

文章目錄實現注冊中心-服務發現模擬掉線遠程調用1.訂單和商品模塊的接口商品服務訂單服務2.抽取實體類3.訂單服務拿到需要調用服務的ip和端口負載均衡步驟1步驟2步驟3步驟4面試題&#xff1a;注冊中心宕機&#xff0c;遠程調用還能成功嗎&#xff1f;1、調用過;遠程調用不在依賴…

【Python】數據可視化之熱力圖

熱力圖&#xff08;Heatmap&#xff09;是一種通過顏色深淺來展示數據分布、密度和強度等信息的可視化圖表。它通過對色塊著色來反映數據特征&#xff0c;使用戶能夠直觀地理解數據模式&#xff0c;發現規律&#xff0c;并作出決策。 目錄 基本原理 sns.heatmap 代碼實現 基…

如何 正確使用 nrm 工具 管理鏡像源

目錄 nrm 是啥&#xff1f; nrm 的安裝 查看你當前已有的鏡像源 怎么切換到目標鏡像源 添加鏡像源 刪除鏡像源 測試鏡像源速度 nrm 是啥&#xff1f; 鏡像源&#xff1a;可以理解為&#xff0c;你訪問或下載某jar包或依賴的倉庫。 nrm&#xff08;Node Registry Manag…

關于對逾期提醒的定時任務~改進完善

Spring Boot 中實現到期提醒任務的定時Job詳解在金融或借貸系統中&#xff0c;到期提醒是常見的功能需求。通過定時任務&#xff0c;可以定期掃描即將到期的借款記錄&#xff0c;并生成或更新提醒信息。本文基于提供的三個JobHandler類&#xff08;FarExpireRemindJob、MidExpi…

springboot配置請求日志

springboot配置請求日志 一般情況下&#xff0c;接口請求都需要日志記錄&#xff0c;Java springboot中的日志記錄相對復雜一點 經過實踐&#xff0c;以下方案可行&#xff0c;記錄一下完整過程 一、創建日志數據模型 創建實體類&#xff0c;也就是日志文件中要記錄的數據格式 …

Redis(50) Redis哨兵如何與客戶端進行交互?

Redis 哨兵&#xff08;Sentinel&#xff09;不僅負責監控和管理 Redis 主從復制集群的高可用性&#xff0c;還需要與客戶端進行有效的交互來實現故障轉移后的透明連接切換。下面詳細探討 Redis 哨兵如何與客戶端進行交互&#xff0c;并結合代碼示例加以說明。 哨兵與客戶端的交…

【.Net技術棧梳理】04-核心框架與運行時(線程處理)

文章目錄1. 線程管理1.1 線程的核心概念&#xff1a;System.Threading.Thread1.2 現代線程管理&#xff1a;System.Threading.Tasks.Task 和 Task Parallel Library (TPL)1.3 狀態管理和異常處理1.4 協調任務&#xff1a;async/await 模式2. 線程間通信2.1 共享內存與競態條件2…

(JVM)四種垃圾回收算法

在 JVM 中&#xff0c;垃圾回收&#xff08;GC&#xff09;是核心機制之一。為了提升性能與內存利用率&#xff0c;JVM 采用了多種垃圾回收算法。本文總結了 四種常見的 GC 算法&#xff0c;并結合其優缺點與應用場景進行說明。1. 標記-清除&#xff08;Mark-Sweep&#xff09;…

論文閱讀:VGGT Visual Geometry Grounded Transformer

論文閱讀&#xff1a;VGGT: Visual Geometry Grounded Transformer 今天介紹一篇 CVPR 2025 的 best paper&#xff0c;這篇文章是牛津大學的 VGG 團隊的工作&#xff0c;主要圍繞著 3D 視覺中的各種任務&#xff0c;這篇文章提出了一種多任務統一的架構&#xff0c;實現一次輸…

python編程:一文掌握pypiserver的詳細使用

更多內容請見: python3案例和總結-專欄介紹和目錄 文章目錄 一、 pypiserver 概述 1.1 pypiserver是什么? 1.2 核心特性 1.3 典型應用場景 1.4 pypiserver優缺點 二、 安裝與基本使用 2.1 安裝 pypiserver 2.2 快速啟動(最簡模式) 2.3 使用私有服務器安裝包 2.4 向私有服務…

Git reset 回退版本

- 第 121 篇 - Date: 2025 - 09 - 06 Author: 鄭龍浩&#xff08;仟墨&#xff09; 文章目錄Git reset 回退版本1 介紹三種命令區別3 驗證三種的區別3 如果不小心git reset --hard將「工作區」和「暫存區」中的內容刪除&#xff0c;剛才的記錄找不到了&#xff0c;怎么辦呢&…

ARM 基礎(2)

ARM內核工作模式及其切換條件用戶模式(User Mode, usr) 權限最低&#xff0c;運行普通應用程序。只能通過異常被動切換到其他模式。快速中斷模式(FIQ Mode, fiq) 處理高速外設中斷&#xff0c;專用寄存器減少上下文保存時間&#xff0c;響應周期約4個時鐘周期。觸發條件為FIQ中…