力扣刷题——DFS深度优先搜索算法

  1. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,
请你计算网格中岛屿的数量。
岛屿总是被水包围,
并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:
[
[‘1’,‘1’,‘1’,‘1’,‘0’],
[‘1’,‘1’,‘0’,‘1’,‘0’],
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘0’,‘0’,‘0’,‘0’,‘0’]
]
输出: 1

示例 2:
输入:
[
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘1’,‘1’,‘0’,‘0’,‘0’],
[‘0’,‘0’,‘1’,‘0’,‘0’],
[‘0’,‘0’,‘0’,‘1’,‘1’]
]
输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

思路DFS深度优先搜索算法
循环遍历数组,每次走一格,每走一格,判断是否为岛屿,如果是,岛屿数量加一,并执行一次“探索”

在“探索”函数中,把当前值标记为“走过”,并把周围所有岛屿探索一遍
所以在外层函数中,只要判断当前位置是否存在岛屿,存在则加一即可
这里不用担心重复,因为我们在探索函数中已经把附近情况排除掉了

void
dfs_fun(char** grid, int gridSize, int gridColSize, int i, int j) {
    
    
    if (i < 0 || i >= gridSize || j < 0 || j >= gridColSize || grid[i][j] != '1') {
    
    
        return;     //如果当前元素不符合要求:越界或者不为岛屿,直接返回
    } else {
    
              //如果当前元素符合要求,则进行标志并找寻周围所有岛屿
        grid[i][j] = 'x';   //标记当前位置,并向四周探索
        dfs_fun(grid, gridSize, gridColSize, i, j - 1);
        dfs_fun(grid, gridSize, gridColSize, i - 1, j);
        dfs_fun(grid, gridSize, gridColSize, i, j + 1);
        dfs_fun(grid, gridSize, gridColSize, i + 1, j);
    }
}


int 
numIslands(char** grid, int gridSize, int* gridColSize) {
    
    
    int cnt = 0;    //用于记录岛屿数量
    for (int i = 0; i < gridSize; i++) {
    
      //两层循环用于遍历每个元素
        for (int j = 0; j < gridColSize[0]; j++) {
    
    
            if (grid[i][j] == '1') {
    
        //如果当前为岛屿
                cnt++;  //岛屿数量加一,并向四周探索
                dfs_fun(grid, gridSize, gridColSize[0], i, j);
            }
        }
    } return cnt;
}

.
.
.

  1. 岛屿的周长

给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。
网格中的格子水平和垂直方向相连(对角线方向不相连)。
整个网格被水完全包围,但其中恰好有一个岛屿
(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。
格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。
计算这个岛屿的周长。

示例 :
输入:
[[0,1,0,0],
[1,1,1,0],
[0,1,0,0],
[1,1,0,0]]
输出: 16
解释: 它的周长是下面图片中的 16 个黄色的边:
在这里插入图片描述

思路DFS深度优先搜索算法
循环遍历数组,每次走一格,每走一格,判断是否为岛屿,如果是,直接从当前位置开始“探索”,并返回结果。

一次探索,就能够把所有结果探索出来——因为根据题意只有一个岛屿,不会有多个岛屿的情况。

在“探索”函数中,如果当前位置为越界或者海洋,则说明与原本的陆地有1个交接处,故返回1;如果当前位置已经被走过,则说明与其是相通的,之间不会有交接,故没有边界,所以返回0;如果当前位置为1,标记为走过,然后向四周探索,将探索结果求和返回。

int
dfs_fun(int** grid, int gridSize, int gridColSize, int i, int j) {
    
    
    if (i < 0 || i >= gridSize || j < 0 || j >= gridColSize || grid[i][j] == 0) {
    
    
        return 1;   //不符合要求:越界、遇到海洋,则只有一个边界
    } else if (grid[i][j] == 8) {
    
    
        return 0;   //如果已经走过了,就返回0
    } else {
    
      //grid[i][j]==1,当前为探索到的新大陆
        grid[i][j] = 8; //标记为走过,同时向四周探索新大陆
        return dfs_fun(grid, gridSize, gridColSize, i, j + 1) +
               dfs_fun(grid, gridSize, gridColSize, i, j - 1) +
               dfs_fun(grid, gridSize, gridColSize, i + 1, j) +
               dfs_fun(grid, gridSize, gridColSize, i - 1, j);
    }
}


int
islandPerimeter(int** grid, int gridSize, int* gridColSize) {
    
    
    for (int i = 0; i < gridSize; i++) {
    
    
        for (int j = 0; j < gridColSize[0]; j++) {
    
    
            if (grid[i][j] == 1)
                return dfs_fun(grid, gridSize, gridColSize[0], i, j);
        }
    } return -1;
}

.
.
.

  1. 岛屿的最大面积

给定一个包含了一些 0 和 1 的非空二维数组 grid 。
一个岛屿 是由一些相邻的 1 (代表土地) 构成的组合,
这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻
你可以假设 grid 的四个边缘都被 0(代表水)包围着
找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 

示例 1:
输入:
[[0,0,1,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,1,1,0,1,0,0,0,0,0,0,0,0],
[0,1,0,0,1,1,0,0,1,0,1,0,0],
[0,1,0,0,1,1,0,0,1,1,1,0,0],
[0,0,0,0,0,0,0,0,0,0,1,0,0],
[0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出:
6

思路DFS深度优先搜索算法
循环遍历数组,每次走一格,每走一格,判断是否为岛屿,如果是,进行一次探索,将探索的结果与当前的最大值MAX作比较,如果大于MAX则更新。最后输出MAX值即可。

在“探索”函数中,如果当前为岛,则把当前值标记为“走过”——直接把‘1’置为‘0’,把岛屿“沉没”。然后把周围所有岛屿探索一遍,返回1+探索结果。
(注意这里的“1+”,因为当前位置是符合要求的)
如果当前不为岛,则返回0

int
dfs_fun(int** grid, int gridSize, int gridColSize, int i, int j) {
    
    
    if (i < 0 || i >= gridSize || j < 0 || j >= gridColSize || grid[i][j] == 0) {
    
    
        return 0;
    } else {
    
    
        grid[i][j] = 0;
        return dfs_fun(grid, gridSize, gridColSize, i, j + 1) +
            dfs_fun(grid, gridSize, gridColSize, i, j - 1) +
            dfs_fun(grid, gridSize, gridColSize, i + 1, j) +
            dfs_fun(grid, gridSize, gridColSize, i - 1, j) + 1;
    }
}


int
maxAreaOfIsland(int** grid, int gridSize, int* gridColSize) {
    
    
    int max = 0;
    for (int i = 0; i < gridSize; i++) {
    
    
        for (int j = 0; j < gridColSize[0]; j++) {
    
    
            if (grid[i][j] == 1) {
    
    
                int result = dfs_fun(grid, gridSize, gridColSize[0], i, j);
                max = (result > max) ? result : max;
            }
        }
    } return max;
}

.
.
.

  1. 被围绕的区域

给定一个二维的矩阵,包含 'X' 和 'O'(字母 O)。
找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O' 用 'X' 填充。

示例:
X X X X
X O O X
X X O X
X O X X

运行你的函数后,矩阵变为:
X X X X
X X X X
X X X X
X O X X
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

思路DFS深度优先搜索算法
题目要求找到被‘X’包围的‘O’,换种思路,只要与边界上的‘O’直接或间接相连的‘O’都不是被‘X’完全包围的‘O’,都是外围‘O’,所以只要我们把外围‘O’进行深度优先搜索,将其置为‘V’,那么剩下的‘O’即为被‘X’全包围的‘O’

于是我们对数组的外围做遍历,如果遇到外围的‘O’,则进行一次探索,同时把探索过程中遇到的‘O’置为‘V’,表明外围。一次遍历之后,再进行一次遍历,把现有的‘V’替换成‘O’,把现有的‘O’替换成‘X’。

void
dfs_fun(char** board, int boardSize, int boardColSize, int i, int j) {
    
    
    if (i < 0 || i >= boardSize || j < 0 || j >= boardColSize || board[i][j] == 'X' || board[i][j] == 'V') {
    
    
        return; //如果条件不满足:直接return
    } else {
    
      //board[i][j]=='O'  如果当前为‘O’,标志为‘V’表明以探索,并继续探索
        board[i][j] = 'V';
        dfs_fun(board, boardSize, boardColSize, i, j + 1);
        dfs_fun(board, boardSize, boardColSize, i, j - 1);
        dfs_fun(board, boardSize, boardColSize, i + 1, j);
        dfs_fun(board, boardSize, boardColSize, i - 1, j);
    }
}


void
solve(char** board, int boardSize, int* boardColSize) {
    
    
    for (int i = 0; i < boardSize; i++) {
    
     //两层循环,寻找最外围的边界‘O’
        for (int j = 0; j < boardColSize[0]; j++) {
    
    
            if (i == 0 || i == boardSize - 1 || j == 0 || j == boardColSize[0] - 1) {
    
    
                if (board[i][j] == 'O')    //如果在边界找到‘O’,则进行探索
                    dfs_fun(board, boardSize, boardColSize[0], i, j);
            }
        }
    }

    for (int i = 0; i < boardSize; i++) {
    
         //再次遍历数组,更新结果
        for (int j = 0; j < boardColSize[0]; j++) {
    
    
            switch (board[i][j]) {
    
    
            case 'O':   //如果为‘O’,表明是内部‘O’
                board[i][j] = 'X';  //要填充成‘X’
                break;
            case 'V':   //如果为‘V’,表明为外部‘O’
                board[i][j] = 'O';  //要恢复成‘O’
                break;
            case 'X':   //如果为‘X’,不做操作
            default:
                break;
            }
        }
    }
}

.
.
.

剑指 Offer 12. 矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径
路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格
如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子
例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径
(路径中的字母用加粗标出)
[	["a","b","c","e"],
	["s","f","c","s"],
	["a","d","e","e"]		]
但矩阵中不包含字符串“abfb”的路径,
因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,
路径不能再次进入这个格子。

思路DFS深度优先搜索算法
就,字符开头匹配之后就开始深搜,然后遇到字符相符就继续,同时标记当前位,以免重复经过。如果遇到字符不相符或者越界则返回。最后返回深搜结果即可。

注意board[i][j] = ‘#’;和board[i][j] = word[k];这两步,
是要对board操作而不是对word操作

bool
dfs_fun(char** board, int boardSize, int boardColSize, int i, int j, int k, char* word) {
    
    
    if (i < 0 || i >= boardSize || j < 0 || j >= boardColSize || k >= strlen(word) || board[i][j] != word[k]) {
    
    
        return false;   //如果越界或者当前字符不匹配,则返回false
    } else if (k == strlen(word) - 1) {
    
    
        return true;    //如果k达到len-1,且此时字符匹配,则全匹配,返回true
    } else {
    
    
        board[i][j] = '#';  //标记当前位置,避免重复;接下来向四周探索
        bool result = dfs_fun(board, boardSize, boardColSize, i, j + 1, k + 1, word) ||
            dfs_fun(board, boardSize, boardColSize, i, j - 1, k + 1, word) ||
            dfs_fun(board, boardSize, boardColSize, i + 1, j, k + 1, word) ||
            dfs_fun(board, boardSize, boardColSize, i - 1, j, k + 1, word);
        board[i][j] = word[k];  //重新把字符恢复
        return result;
    }
}


bool
exist(char** board, int boardSize, int* boardColSize, char* word) {
    
    
    for (int i = 0; i < boardSize; i++) {
    
       //两层遍历
        for (int j = 0; j < boardColSize[0]; j++) {
    
    
            if (board[i][j] == word[0])     //如果字符开头匹配,则开始探索
                if (dfs_fun(board, boardSize, boardColSize[0], i, j, 0, word))
                    return true;
        }
    } return false;
}

猜你喜欢

转载自blog.csdn.net/weixin_44692935/article/details/108577677