leetcode200_岛屿数量_和130题思路一样_趁热打铁

1.  有了130题的思路就好写多了,放上自己写的代码.

2.  没有用visited记录使用过的值,而是改用不同的符号代替,这是借鉴130题的思路.

3.  搜索的时候四个方向,注意学习.

4.  此题不需要回溯,因为要把所有的1都标记为岛屿,不像79题单词回溯时搜索单词不对要回溯.

class Solution {
public:
	void dfs(int i, int j, vector<vector<char>>& grid) {
		if (i < 0 || i >= grid.size() || j < 0 || j >= grid[0].size())
			return;
		if (grid[i][j] == '#')
			return;
		if (grid[i][j] == '1') {
			grid[i][j] = '#';
			dfs(i + 1, j, grid);
			dfs(i - 1, j, grid);
			dfs(i, j + 1, grid);
			dfs(i, j - 1, grid);
		}
	}
	int numIslands(vector<vector<char>>& grid) {
		if (grid.size() == 0 || grid[0].size() == 0)
			return 0;
		int m = grid.size(), n = grid[0].size();
		int count = 0;
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (grid[i][j] == '1') {
					dfs(i, j, grid);
					count++;
				}
			}
		}
		return count;
	}
};

二.  参考一下大神的理解.

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/number-of-islands/solution/dfs-bfs-bing-cha-ji-python-dai-ma-java-dai-ma-by-l/

1.  这道题是可以使用一个经典的算法来解决的,那就是 Flood fill,以下的定义来自 维基百科:Flood fill 词条。

Flood fill 算法是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典 算法。因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名。在 GNU Go 和 扫雷 中,Flood Fill算法被用来计算需要被清除的区域。

2. 从一个区域中提取若干个连通的点与其他相邻区域区分开.从一个点扩散开,找到与其连通的点,这不是什么高深的算法,其实就是从一个点开始,进行一次 “深度优先遍历” 或者 “广度优先遍历”,通过 “深度优先遍历” 或者 “广度优先遍历” 发现一片连着的区域,对于这道题来说,就是从一个是 “陆地” 的格子开始进行一次 “深度优先遍历” 或者 “广度优先遍历”,把与之相连的所有的格子都标记上,视为发现了一个 “岛屿”。

3.  深度优先遍历在之前写过了, 关键是广度优先遍历. 此时你就不用回溯了.“广度优先遍历” 需要一个 “辅助队列”.(动态图不错)(java代码直接看注释也很好理解.)

/**
* 方法二:广度优先遍历
*/
public class Solution2 {


	private int rows;
	private int cols;

	public int numIslands(char[][] grid) {
		//           x-1,y
		//  x,y-1    x,y      x,y+1
		//           x+1,y
		int[][] directions = { { -1, 0 },{ 0, -1 },{ 1, 0 },{ 0, 1 } };

		rows = grid.length;
		if (rows == 0) {
			return 0;
		}
		cols = grid[0].length;
		boolean[][] marked = new boolean[rows][cols];
		int count = 0;
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				// 如果是岛屿中的一个点,并且没有被访问过
				// 从坐标为 (i,j) 的点开始进行广度优先遍历
				if (!marked[i][j] && grid[i][j] == '1') {
					count++;
					LinkedList<Integer> queue = new LinkedList<>();
					// 小技巧:把坐标转换为一个数字
					// 否则,得用一个数组存,在 Python 中,可以使用 tuple 存
					queue.addLast(i * cols + j);
					// 注意:这里要标记上已经访问过
					marked[i][j] = true;
					while (!queue.isEmpty()) {
						int cur = queue.removeFirst();
						int curX = cur / cols;
						int curY = cur % cols;
						// 得到 4 个方向的坐标
						for (int k = 0; k < 4; k++) {
							int newX = curX + directions[k][0];
							int newY = curY + directions[k][1];
							// 如果不越界、没有被访问过、并且还要是陆地,我就继续放入队列,放入队列的同时,要记得标记已经访问过
							if (inArea(newX, newY) && grid[newX][newY] == '1' && !marked[newX][newY]) {
								queue.addLast(newX * cols + newY);
								// 【特别注意】在放入队列以后,要马上标记成已经访问过,语义也是十分清楚的:反正只要进入了队列,你迟早都会遍历到它
								// 而不是在出队列的时候再标记
								// 【特别注意】如果是出队列的时候再标记,会造成很多重复的结点进入队列,造成重复的操作,这句话如果你没有写对地方,代码会严重超时的
								marked[newX][newY] = true;
							}
						}
					}
				}
			}

		}
		return count;
	}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值