最近学习了深度优先搜索算法(DFS),特针对该算法找了题目来做,该题就是典型的运用了搜索算法的题目
现在先讲一下使用DFS怎么做这道题(BFS暂时未掌握,后续会补上~~)
思路上也比较容易想到
首先我们肯定要先创建二维数组,并且填入一定的数据,之后我们就可以开始遍历该数组了,我们一旦遇到“ 1 ”,我们先把这个“ 1 ”变成“ 0 ”后我们就开始搜索这个1附近的“上下左右”,如果还有“ 1 ”,我们还把它变成“0”之后搜索这个“ 1 ”的“上下左右”,直到附近全为“0”为止
对了还记得我们DFS的模板吗!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
DFS(深度优先搜索算法)入门_ZZZWWWFFF_的博客-CSDN博客
上面的模板是我在这篇博客里面提到过的,感兴趣的同学可以看看
下面就是代码实现啦
因为交题时采用的是“核心代码”模式,所以没有写出“完整”代码
下面有两种DFS的写法(实际上差别不大)
class Solution {
public:
int nextt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n,m,tx,ty,count=0;
int solve(vector<vector<char> >& grid) {
n=grid.size();//计算行数
m=grid[0].size();//计算列数
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(grid[i][j]=='1')
{
count++;
dfs(i,j,grid);
}
}
}
return count;
}
void dfs(int x,int y,vector<vector<char> >& grid)
{
if(grid[x][y]=='1')
{
grid[x][y]='0';
for(int i=0;i<=3;i++)
{
tx=x+nextt[i][0];
ty=y+nextt[i][1];
if(tx < 0 || ty < 0 || tx >= grid.size() || ty >= grid[0].size()){
continue;
}
if(grid[tx][ty]=='1')
dfs(tx,ty,grid);
}
}
}
};
class Solution {
public:
int nextt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int n,m,tx,ty,count=0;
int solve(vector<vector<char> >& grid) {
n=grid.size();//计算行数
m=grid[0].size();//计算列数
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(dfs(i,j,grid))
{
count++;
}
}
}
return count;
}
int dfs(int x,int y,vector<vector<char> >& grid)
{
if(grid[x][y]=='1')
{
grid[x][y]='0';
for(int i=0;i<=3;i++)
{
tx=x+nextt[i][0];
ty=y+nextt[i][1];
if(tx < 0 || ty < 0 || tx >= grid.size() || ty >= grid[0].size()){
continue;
}
if(grid[tx][ty]=='1')
dfs(tx,ty,grid);
}
return 1;
}
return 0;
}
};
下面给出用BFS写的代码
为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 1,则将其加入队列(注意哦,是将其对应的下标存放到队列中的)开始进行广度优先搜索。在广度优先搜索的过程中,每个搜索到的 1 都会被重新标记为 0 直到队列为空,搜索结束。
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int nr = grid.size();//行数
if (!nr) return 0;//判断边界情况
int nc = grid[0].size();//列数
int num_islands = 0;//用于计数
//遍历二维网格
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
//满足条件时进来,否则进入下一次循环
if (grid[r][c] == '1') {
++num_islands;
grid[r][c] = '0';
//定义一个队列,用于存放下标信息
//注意对pair的理解,可以看作是内部有两个元素的结构体
queue<pair<int, int>> neighbors;
neighbors.push({r, c});//将'1'的下标信息入队
while (!neighbors.empty()) {
pair<int,int> rc = neighbors.front();//访问队首元素
neighbors.pop();//队首元素出队
int row = rc.first;//队首元素所对应的行号
int col = rc.second;//队首元素所对应的列号
//将它上下左右的‘1’都同化成‘0’
//上
//row - 1 >= 0 判断位置是否合法
if (row - 1 >= 0 && grid[row-1][col] == '1') {
neighbors.push({row-1, col});
grid[row-1][col] = '0';
}
//下
//row + 1 < nr 判断位置是否合法
if (row + 1 < nr && grid[row+1][col] == '1') {
neighbors.push({row+1, col});
grid[row+1][col] = '0';
}
//左
//col - 1 >= 0 判断位置是否合法
if (col - 1 >= 0 && grid[row][col-1] == '1') {
neighbors.push({row, col-1});
grid[row][col-1] = '0';
}
//右
//col + 1 < nc 判断位置是否合法
if (col + 1 < nc && grid[row][col+1] == '1') {
neighbors.push({row, col+1});
grid[row][col+1] = '0';
}
}
}
}
}
return num_islands;
}
};
以上代码较为冗长,若读者无法理解,这边建议自己调试一遍
下面是并查集的写法
思路是我们遍历整个数组,如果一个‘1’周围有‘1’,就把它们并起来
class Solution {
public:
int n, m,ans=0, nextt[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };
void init(int father[])
{
for (int i = 0; i < n * m; i++)//初始化自己为根
{
father[i] = i;
}
}
int find(int x, int father[])//寻找根 同时压缩路径
{
if (father[x] == x)
{
return x;
}
else
{
return father[x] = find(father[x], father);
}
}
void join(int a, int b, int father[])
{
int root1 = find(a, father);
int root2 = find(b, father);
if (root1 != root2)
{
father[root2] = root1;
ans--;//注意并起来之后--(因为并起来之后就是一个岛屿)
}
}
int numIslands(vector<vector<char>>& grid) {
n = grid.size();
m = grid[0].size();
int* father = new int[n * m];
init(father);//初始化
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (grid[i][j] == '1')
{
ans++;//计算岛屿数量(假设每一个都是岛屿)
for (int z = 0; z < 4; z++)//将周围的'1'并起来
{
int tx = i + nextt[z][0];
int ty = j + nextt[z][1];
if (tx < 0 || ty < 0 || tx >= n || ty >= m)//判断是否越界
{
continue;
}
if (grid[tx][ty] == '1')
{
join(i * m + j, tx * m + ty, father);///并起来
}
}
}
}
}
delete[]father;//记得delete
return ans;
}
};