给你一个由 '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;
}
.
.
.
给定一个包含 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;
}
.
.
.
给定一个包含了一些 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;
}
.
.
.
给定一个二维的矩阵,包含 '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;
}