C++遞歸算法處理島嶼問題詳解
島嶼問題定義
島嶼問題是指用二維數(shù)組進行模擬, 1的位置表示陸地, 0的位置表示海洋。島嶼是指 被水(0)包圍的陸地(1) 如下圖所示:

島嶼問題是一道典型的遞歸問題(一位大佬曾說將島嶼問題看成是4叉樹,我覺得這個比喻非常好), 對每個陸地位置, 我們需要遞歸地檢測它的上下左右位置是不是陸地。
下面我們來寫一下對島嶼問題的遞歸模板:
public void dfs(char[][] grid, int m, int n){
// 位置越界 或者 該位置已經(jīng)被遍歷過
if(isBeyond(grid, m, n) || grid[m][n] == 2){
return;
}
// 相應操作
........
// 記錄已經(jīng)遍歷過位置
grid[m][n] = '2';
// 遞歸遍歷該陸地位置的上下左右位置
dfs(grid, m-1, n);
dfs(grid, m+1, n);
dfs(grid, m, n-1);
dfs(grid, m, n+1);
}
// 檢測越界的函數(shù)
boolean isBeyond(char[][] grid, int m, int n){
if(m < 0 || m>=grid.length || n<0 || n>=grid[0].length){
return true;
}
return false;
}這里說明一下,島嶼問題中的備忘錄問題,為什么在遞歸的過程中需要建立這樣一個備忘錄,我們可以看如下圖解:
如果不建立備忘錄,在遞歸過程中,可能會出現(xiàn)同一位置被多次遞歸調用的情況,這樣增加了時間復雜度
備忘錄實現(xiàn)方法 : 本題的備忘錄實現(xiàn)非常簡單, 只需將已經(jīng)遍歷過的位置的值修改為2即可

例題一-島嶼的數(shù)量
題目描述: 求一個二維數(shù)組中存在的島嶼數(shù)量
對本題我們直接調用上述模板即可
class Solution {
public int numIslands(char[][] grid) {
int m = grid.length;
int n = grid[0].length;
int ans = 0;
for(int i=0; i<m; i++){
for(int j=0; j<n;j++){
if(grid[i][j] == '1'){
// 遞歸過程中將屬于同一島嶼的位置標記為2,保證屬于同一島嶼的陸地1位置不會重復進入循環(huán)
dfs(grid, i, j);
ans++;
}
}
}
return ans;
}
public void dfs(char[][] grid, int m, int n){
if(isBeyond(grid, m, n)){
return;
}
if(grid[m][n] != '1'){
return;
}
grid[m][n] = '2';
dfs(grid, m-1, n);
dfs(grid, m+1, n);
dfs(grid, m, n-1);
dfs(grid, m, n+1);
}
boolean isBeyond(char[][] grid, int m, int n){
if(m < 0 || m>=grid.length || n<0 || n>=grid[0].length){
return true;
}
return false;
}
}例題二-島嶼的周長
ps:輸入保證只有一個島嶼
分析:
我們可以分析每一個陸地元素,對結果的貢獻度,如下圖解,經(jīng)過分析可得,當陸地與海洋接壤一次或者越界一次對島嶼總周長的貢獻度+1

代碼
class Solution {
// 從一個陸地方塊走向一個非陸地方塊,就將島嶼面積加1
public int islandPerimeter(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int perimeter = 0;
for(int i=0; i<m; i++){
for(int j=0; j<n; j++){
if(grid[i][j] == 1){
// 因為只有一個島嶼,直接返回即可
return getPerimeter(grid, i, j);
}
}
}
return 0;
}
public int getPerimeter(int[][] grid, int m, int n){
// 走到非陸地方塊,返回共享度1
if(isBeyond(grid, m, n) || grid[m][n] == 0){
return 1;
}
// 走到遍歷過方塊返回0
if(grid[m][n] == 2){
return 0;
}
// 標記已經(jīng)遍歷過節(jié)點
grid[m][n] = 2;
return getPerimeter(grid, m-1, n)
+ getPerimeter(grid, m+1, n)
+ getPerimeter(grid, m, n-1)
+ getPerimeter(grid, m, n+1);
}
boolean isBeyond(int[][] grid, int m, int n){
if(m < 0 || n < 0 || m >= grid.length || n >= grid[0].length){
return true;
}
return false;
}
}到此這篇關于C++遞歸算法處理島嶼問題詳解的文章就介紹到這了,更多相關C++島嶼問題內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C語言循環(huán)隊列與用隊列實現(xiàn)棧問題解析
循環(huán)隊列又叫環(huán)形隊列,是一種特殊的隊列。循環(huán)隊列解決了隊列出隊時需要將所有數(shù)據(jù)前移一位的問題,本篇帶你一起看看循環(huán)隊列的問題和怎樣用隊列實現(xiàn)棧2022-04-04
C語言查找數(shù)組里數(shù)字重復次數(shù)的方法
這篇文章主要介紹了C語言查找數(shù)組里數(shù)字重復次數(shù)的方法,涉及C語言針對數(shù)組的遍歷與判斷技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07
C語言實現(xiàn)數(shù)組的循環(huán)左移,右移,翻轉的示例
今天小編就為大家分享一篇C語言實現(xiàn)數(shù)組的循環(huán)左移,右移,翻轉的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07
tinyxml 常用的C++ XML解析器非常優(yōu)秀
讀取和設置xml配置文件是最常用的操作,試用了幾個C++的XML解析器,個人感覺TinyXML是使用起來最舒服的,因為它的API接口和Java的十分類似,面向對象性很好2012-11-11
VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法
本文主要介紹了VS未找到框架“.NETFramework,Version=v4.6.1”引用程序集的解決辦法,具有一定的參考價值,感興趣的可以了解一下2023-10-10
Visual?Studio?2022使用MinGW來編譯調試C/C++程序的圖文教程
這篇文章主要介紹了Visual?Studio?2022使用MinGW來編譯調試C/C++程序,以實例來簡單介紹一下VS2022中如何使用MinGW來編譯、調試C/C++程序,需要的朋友可以參考下2022-08-08

