昨天猿辅导一面时,面试官考了这道岛屿数量的题,问我思路,我说从头遍历矩阵,每遇到一个1,就往下搜,把和它相连的1都置0,但自己又有些地方想不明白,面试官提醒我,想一想搜索算法有哪些?我说有BFS和DFS,面试官提示我可以用一个矩阵记录状态,再用搜索算法,他问我DFS是不是可以,我说是,但无奈DFS不熟,相对还是BFS好写一点,就比较慌乱的用BFS写,但最后卡着点写完,还有一些Bug,今天复盘一下,并在leetcode上验证。
1.题目
给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
示例:
2.思路
思路是每遇到一个1就将land数加1,并且需要保证当前位置和所有与它相连的1都不会再被访问到。输入是一个二维char型vector,我们可以定义一个同等大小bool型vector hasVisited用来存输入矩阵中的点是否被访问过。
首先遍历输入vector grid,每当遇到还未访问过的1,就将land值加1,并将hasVisited中当前位置和所有与它相连的1的位置都设置为true[通过BFS或DFS的思想]
BFS的思想:当dequei不为空时,获得dequei和dequej队头元素i,j,并将i,j位置周围四个位置符合条件[在矩阵范围内,值为‘1’,尚未被访问过]的位置的坐标分别入队列,并将hasVisited矩阵中对应位置设为true,表示这个位置已经被访问过了。
DFS的思想:先向左搜索置最深处,并将搜索到的每个为1的点对应hasVisited矩阵中对应位置设为true,再向右,向上,向下搜索致最深处。
3.代码:
BFS实现:
int numIslands(vector<vector<char>>& grid)
{
//定义初始化访问记录矩阵
int m = grid.size();
if (m == 0)
return 0;
int n = grid[0].size();
vector <vector<bool>> hasVisited(m, vector <bool>(n, false));
deque <int> quei;
deque <int> quej;
int land = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if ((grid[i][j] == '1') && (hasVisited[i][j] == false))
{
quei.push_back(i);
quej.push_back(j);
hasVisited[i][j] = true;
land++;
}
while (!quei.empty())
{
int tmpi = quei.front();
int tmpj = quej.front();
quei.pop_front();
quej.pop_front();
if ((tmpi - 1 >= 0) && (grid[tmpi - 1][tmpj] == '1') &&(hasVisited[tmpi - 1][tmpj] == false))
{
quei.push_back(tmpi - 1);
quej.push_back(tmpj);
hasVisited[tmpi - 1][tmpj] = true;
}
if ((tmpi + 1 < m) && (grid[tmpi + 1][tmpj] == '1') && (hasVisited[tmpi + 1][tmpj] == false))
{
quei.push_back(tmpi + 1);
quej.push_back(tmpj);
hasVisited[tmpi + 1][tmpj] = true;
}
if ((tmpj - 1 >= 0) && (grid[tmpi][tmpj - 1] == '1') && (hasVisited[tmpi][tmpj - 1] == false))
{
quei.push_back(tmpi);
quej.push_back(tmpj - 1);
hasVisited[tmpi][tmpj - 1] = true;
}
if ((tmpj + 1 < n) && (grid[tmpi][tmpj + 1] == '1') && (hasVisited[tmpi][tmpj + 1] ==false))
{
quei.push_back(tmpi);
quej.push_back(tmpj + 1);
hasVisited[tmpi][tmpj + 1] = true;
}
}
}
return land;
}
DFS实现:
void dfs(int i,int j,vector<vector<char>>& grid,vector <vector<bool>> & hasVisited,int m,int n)
{
if ((i - 1 >= 0) && (grid[i - 1][j] == '1') &&(hasVisited[i - 1][j] == false))
{
hasVisited[i - 1][j] = true;
dfs(i-1,j,grid,hasVisited,m,n);
}
if ((i + 1 < m) && (grid[i + 1][j] == '1') && (hasVisited[i + 1][j] == false))
{
hasVisited[i + 1][j] = true;
dfs(i+1,j,grid,hasVisited,m,n);
}
if ((j - 1 >= 0) && (grid[i][j - 1] == '1') && (hasVisited[i][j - 1] == false))
{
hasVisited[i][j - 1] = true;
dfs(i,j-1,grid,hasVisited,m,n);
}
if ((j + 1 < n) && (grid[i][j + 1] == '1') && (hasVisited[i][j + 1] ==false))
{
hasVisited[i][j + 1] = true;
dfs(i,j+1,grid,hasVisited,m,n);
}
}
int numIslands(vector<vector<char>>& grid)
{
//定义初始化访问记录矩阵
int m = grid.size();
if (m == 0)
return 0;
int n = grid[0].size();
vector <vector<bool>> hasVisited(m, vector <bool>(n, false));
int land = 0;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if ((grid[i][j] == '1') && (hasVisited[i][j] == false))
{
hasVisited[i][j] = true;
dfs(i,j,grid,hasVisited,m,n);
land++;
}
}
return land;
}
小结:DFS和BFS的题实际之前在做剑指offer时都做过,但不熟,但面试题常有,还需多练!