面试题之leetcode第200题:岛屿的数量

1,340 阅读3分钟

昨天猿辅导一面时,面试官考了这道岛屿数量的题,问我思路,我说从头遍历矩阵,每遇到一个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时都做过,但不熟,但面试题常有,还需多练!