DFS/BFS
leetcode1254. 统计封闭岛屿的数量
1. 题目
有一个二维矩阵 grid,每个位置要么是陆地(记号为0 )要么是水域(记号为1 )。
我们从一块陆地出发,每次可以往上下左右4 个方向相邻区域走,能走到的所有陆地区域,我们将其称为一座「岛屿」。
如果一座岛屿完全由水域包围,即陆地边缘上下左右所有相邻区域都是水域,那么我们将其称为 「封闭岛屿」。
请返回封闭岛屿的数目。
输入:
grid =
[[1,1,1,1,1,1,1,0],[1,0,0,0,0,1,1,0],[1,0,1,0,1,1,1,0],[1,0,0,0,0,1,0,1],[1,1,1,1,1,1,1,0]]
输出:2
2. 解答
/*
1.先处理四条边;
2.剩下的都是被包围的岛屿
*/
void dfs(int** grid, int row, int col, int x, int y)
{
if (x < 0 || y < 0 || x >= row || y >= col || grid[x][y] == 1) {
return;
}
grid[x][y] = 1;
dfs(grid, row, col, x - 1, y);
dfs(grid, row, col, x + 1, y);
dfs(grid, row, col, x, y - 1);
dfs(grid, row, col, x, y + 1);
return;
}
int closedIsland(int** grid, int gridSize, int* gridColSize) {
int count = 0;
/* 先把地图边上的陆地变为海洋 */
for (int i = 0; i < gridSize; i++) {
dfs(grid, gridSize, *gridColSize, i, 0);
dfs(grid, gridSize, *gridColSize, i, *gridColSize - 1);
}
for (int i = 0; i < *gridColSize; i++) {
dfs(grid, gridSize, *gridColSize, 0, i);
dfs(grid, gridSize, *gridColSize, gridSize - 1, i);
}
/* 剩下的都是被包围的了 */
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < *gridColSize; j++) {
if (grid[i][j] == 0) {
dfs(grid, gridSize, *gridColSize, i, j);
count++;
}
}
}
return count;
}
leetcode79. 单词搜索
1. 题目
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]
给定 word = “ABCCED”, 返回 true
给定 word = “SEE”, 返回 true
给定 word = “ABCB”, 返回 false
2. 解答
bool isExist(char **board, int row, int col, char *word, int x, int y)
{
if (*word == '\0') {
return true;
}
if (x < 0 || y < 0 || x >= row || y >= col || board[x][y] != *word) {
return false;
}
board[x][y] = '\0';
int res = isExist(board, row, col, word + 1, x + 1, y) ||
isExist(board, row, col, word + 1, x - 1, y) ||
isExist(board, row, col, word + 1, x, y + 1) ||
isExist(board, row, col, word + 1, x, y - 1);
board[x][y] = *word;
return res;
}
bool exist(char** board, int boardSize, int* boardColSize, char * word) {
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < *boardColSize; j++) {
if (board[i][j] == word[0] && isExist(board, boardSize, *boardColSize, word, i, j)) {
return true;
}
}
}
return false;
}
leetcode695. 岛屿的最大面积
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。注意答案不应该是 11 ,因为岛屿只能包含水平或垂直的四个方向的 1 。
示例 2:
[[0,0,0,0,0,0,0,0]]
2. 解答
int dfs(int **grid, int row, int col, int x, int y)
{
int res = 1;
if (x < 0 || y < 0 || x >= row || y >= col || grid[x][y] == 0) {
return 0;
}
grid[x][y] = 0;
res += dfs(grid, row, col, x + 1, y) + dfs(grid, row, col, x - 1, y) +
dfs(grid, row, col, x, y + 1) + dfs(grid, row, col, x, y - 1);
return res;
}
int maxAreaOfIsland(int** grid, int gridSize, int* gridColSize)
{
int res = 0;
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < *gridColSize; j++) {
if (grid[i][j] == 1) {
int temp = dfs(grid, gridSize, *gridColSize, i, j);
if (temp > res) {
res = temp;
}
}
}
}
return res;
}
剑指offer13. 机器人的运动范围
1. 题目
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1
提示:
1 <= n,m <= 100
0 <= k <= 20
2. 解答
int dfs(int i, int j, int m, int n, int k, int **isVisted)
{
if (i <0 || i >= m || j<0 || j>=n || (i / 10 + i % 10 + j / 10 + j % 10)>k || isVisted[i][j] == 1) {
return 0;
}
isVisted[i][j] = 1;
return dfs(i + 1, j, m, n, k, isVisted) + dfs(i - 1, j, m, n, k, isVisted) +
dfs(i, j + 1, m, n, k, isVisted) + dfs(i, j - 1, m, n, k, isVisted) + 1;
}
int movingCount(int m, int n, int k) {
int **isVisted = (int **)malloc(sizeof(int *) * m);
for (int i = 0; i < m; i++) {
isVisted[i] = (int *)malloc(sizeof(int) *n);
memset(isVisted[i], 0, sizeof(int) *n);
}
return dfs(0, 0, m, n, k, isVisted);
}
leetcode934. 最短的桥
1. 题目
在给定的二维二进制数组A中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将0变为1,以使两座岛连接起来,变成一座岛。
返回必须翻转的0 的最小数目。(可以保证答案至少是 1。)
示例 1:
输入:[[0,1],[1,0]]
输出:1
示例 2:
输入:[[0,1,0],[0,0,0],[0,0,1]]
输出:2
示例 3:
输入:[[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]]
输出:1
2. 解答
思路:
(1)先用DFS将其中一座岛置为2,和另一座区别开
(2)用BFS,将置为2的那座岛,一层层往外填海,直到第一次遇到另一座岛,就是最短的距离点
struct Point {
int x;
int y;
};
#define ROWSIZE 4
#define COLSIZE 2
int g_direction[ROWSIZE][COLSIZE] = {{ 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 }};
void dfs(int **A, int row, int col, int x, int y)
{
for (int i = 0; i < ROWSIZE; i++) {
int newX = x + g_direction[i][0];
int newY = y + g_direction[i][1];
if (newX >= 0 && newX < row && newY >= 0 && newY < col && A[newY][newY] == 1) {
A[newX][newY] = 2;
dfs(A, ASize, AColSize, newX, newY);
}
}
}
int shortestBridge(int** A, int ASize, int* AColSize)
{
if (A == NULL) {
return 0;
}
int result = 0;
bool flag = false;
/* 找出第一个岛并标记为2 */
for (int i = 0; i < ASize; i++) {
for (int j = 0; j < *AColSize; j++) {
if (A[i][j] == 1) {
flag = true;
A[i][j] = 2;
dfs(A, ASize, *AColSize, i, j);
break;
}
}
if (flag) {
break;
}
}
/* 将2放入到队列中 */
struct Point *p = (struct Point *)malloc(sizeof(struct Point) * ASize * (*AColSize));
if (p != NULL) {
memset(p, 0, sizeof(struct Point) * ASize * (*AColSize));
}
int index = 0;
for (int i = 0; i < ASize; i++) {
for (int j = 0; j < *AColSize; j++) {
if (A[i][j] == 2) {
p[index].x = i;
p[index].y = j;
index++;
}
}
}
/* BFS找到2到1的最短距离 */
int head = 0;
int tail = index;
while (head < tail) {
int tempH = head;
int tempT = tail;
for (int i = tempH; i < tempT; i++) {
struct Point tempP;
tempP.x = p[i].x;
tempP.y = p[i].y;
for (int j = 0; j < ROWSIZE; j++) {
int newX = tempP.x + g_direction[j][0];
int newY = tempP.y + g_direction[j][1];
if (!(newX >= 0 && newX < ASize && newY >= 0 && newY < *AColSize)) {
continue;
}
if (A[newX][newY] == 2) {
continue;
}
if (A[newX][newY] == 1) {
free(p);
return result;
}
// 把该点放入队列,进入下一个循环
p[tail].x = newX;
p[tail].y = newY;
tail++;
A[newX][newY] = 2;
}
}
// 上一轮都遍历完了,下一轮从这个位置开始
head = tempT;
result++;
}
free(p);
return result;
}