LeetCode 200:岛屿数量 Number of Islands
题目:
给定一个由 '1'
(陆地)和 '0'
(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。
Given a 2d grid map of '1'
s (land) and '0'
s (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
示例 1:
输入:
11110
11010
11000
00000
输出: 1
示例 2:
输入:
11000
11000
00100
00011
输出: 3
解题思路:
首先明白岛屿的定义:一块 1 周围全是 0,即为一个岛屿。(注意:grid 数组内的 1、0 均为char型字符,非整型)
示例1 中所有 1 都可以连接到一起,即所有 1 组成一个岛屿。示例2 中的三个岛屿:左上角四个1、中间一个1、右下角一个一,分别组成三个岛屿。
Flood fill算法是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法。因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名。在 GNU Go 和 扫雷 中,Flood Fill算法被用来计算需要被清除的区域。由上述定义可看出该题是典型的Flood fill算法类型例题,将岛屿与水分开,并染成特定颜色,以记录已累加过该岛屿。
每块岛屿可以看成相连的一个个节点,只需把所有相连节点遍历殆尽并标上特殊值以记录该节点已访问过,则遍历殆尽时证明一块岛屿已找到。
三种解题方法:
DFS(深度优先搜索):从一个为1的根节点开始访问,从每个相邻1节点向下访问到顶点(周围全是水),依次访问其他相邻1节点到顶点
BFS(广度优先搜索):从一个为1的根节点开始访问,每次向下访问一个节点,直到访问到最后一个顶点
并查集:也被称为联合查找数据结构,因为它主要由联合、查找两个过程实现:
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
针对该题即 先以一个根节点1作为初始节点,判断周围节点是否为1,如果是则新建一个集合并把该节点作为父节点。之后遍历下一个节点,如果是1则查找该节点的父节点(即第一个节点),并把该节点周围为1的节点的父节点全部指向该节点的父节点,以此类推,直到把该块岛屿所有1 节点加入同一个集合。最后集合个数(父节点的个数)即为岛屿数量
DFS:
时间复杂度 : O(M×N),其中 M 和 N 分别为行数和列数。
空间复杂度 : 最坏情况下为 O(M×N),此时整个网格均为陆地,深度优先搜索的深度达到 M×N。
Java:
class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
int row = grid.length, columns = grid[0].length, count = 0;
for (int i = 0; i < row; i++) {//遍历所有点
for (int j = 0; j < columns; j++) {
if (grid[i][j] == '1') {
dfs(grid, i, j, row, columns);//dfs遍历所有连接的点
count++;//记录岛屿数量
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j, int row, int columns) {
if (i < 0 || j < 0 || i >= row || j >= columns || grid[i][j] == '0') return;//基线条件
grid[i][j] = '0';//遍历过的点置 0
dfs(grid, i + 1, j, row, columns);
dfs(grid, i, j + 1, row, columns);
dfs(grid, i - 1, j, row, columns);
dfs(grid, i, j - 1, row, columns);
}
}
Python:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if not grid or len(grid) == 'o': return 0
row, columns = len(grid), len(grid[0])
count = 0
for i in range(row):
for j in range(columns):
if grid[i][j] == '1':
self.dfs(grid, i, j, row, columns)
count += 1
return count
def dfs(self, grid: List[List[str]], i: int, j: int, row: int, columns: int):
if i >= row or i < 0 or j >= columns or j < 0 or grid[i][j] == '0': return
grid[i][j] = '0'
self.dfs(grid, i - 1, j, row, columns)
self.dfs(grid, i, j - 1, row, columns)
self.dfs(grid, i + 1, j, row, columns)
self.dfs(grid, i, j + 1, row, columns)
BFS:
时间复杂度 : O(M×N),其中 M 和 N 分别为行数和列数。
空间复杂度 : O( min(M,N) ),在最坏的情况下(全部为陆地),队列的大小可以达到 min(M,N)。
Java:
class Solution {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
int row = grid.length, columns = grid[0].length, count = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < columns; j++) {//遍历所有节点
if (grid[i][j] == '1') {
bfs(grid, i, j, row, columns);
count++;//记录岛屿数量
}
}
}
return count;
}
private void bfs(char[][] grid, int i, int j, int row, int columns) {
Queue<Integer> loc = new LinkedList<>();//队列暂存值为 1 的点
loc.add(i * columns + j);//暂存该点位置,也可以用一个[i,j]数组表示,不过占用空间也会大一倍
while (!loc.isEmpty()) {
int id = loc.remove();//取出位置
int r = id / columns, c = id % columns;//分解位置得到索引
if (r - 1 >= 0 && grid[r - 1][c] == '1') {
loc.add((r - 1) * columns + c);
grid[r - 1][c] = '0';
}
if (r + 1 < row && grid[r + 1][c] == '1') {
loc.add((r + 1) * columns + c);
grid[r + 1][c] = '0';
}
if (c - 1 >= 0 && grid[r][c - 1] == '1') {
loc.add(r * columns + c - 1);
grid[r][c - 1] = '0';
}
if (c + 1 < columns && grid[r][c + 1] == '1') {
loc.add(r * columns + c + 1);
grid[r][c + 1] = '0';
}
}
}
}
Python3:
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
if not grid or len(grid) == 'o': return 0
row, columns = len(grid), len(grid[0])
count = 0
for i in range(row):
for j in range(columns):
if grid[i][j] == '1':
self.bfs(grid, i, j, row, columns)
count += 1
return count
def bfs(self, grid: List[List[str]], i: int, j: int, row: int, columns: int):
queue = collections.deque()
queue.append((i, j)) # 位置以元组存入队列
while queue:
r, c = queue.popleft()
if r + 1 < row and grid[r + 1][c] == '1':
queue.append((r + 1, c))
grid[r + 1][c] = '0'
if r - 1 >= 0 and grid[r - 1][c] == '1':
queue.append((r - 1, c))
grid[r - 1][c] = '0'
if c + 1 < columns and grid[r][c + 1] == '1':
queue.append((r, c + 1))
grid[r][c + 1] = '0'
if c - 1 >= 0 and grid[r][c - 1] == '1':
queue.append((r, c - 1))
grid[r][c - 1] = '0'
并查集:
并查集这种解法冗杂且鸡肋,效率很低,以下java代码参考自LeetCode。简单了解其思想扩展一下思路即可:
Java:
class Solution {
class UnionFind {
int count; //计数
int[] parent;
int[] rank;
public UnionFind(char[][] grid) {
count = 0;
int m = grid.length, n = grid[0].length;
parent = new int[m * n];
rank = new int[m * n];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (grid[i][j] == '1') {
parent[i * n + j] = i * n + j;
++count;
}
rank[i * n + j] = 0;
}
}
}
public int find(int i) {
if (parent[i] != i) parent[i] = find(parent[i]);
return parent[i];
}
public void union(int x, int y) {
int rootx = find(x);
int rooty = find(y);
if (rootx != rooty) {
if (rank[rootx] > rank[rooty]) {
parent[rooty] = rootx;
} else if (rank[rootx] < rank[rooty]) {
parent[rootx] = rooty;
} else {
parent[rooty] = rootx;
rank[rootx] += 1;
}
--count;
}
}
public int getCount() {
return count;
}
}
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
int row = grid.length, columns = grid[0].length;
UnionFind uf = new UnionFind(grid);
for (int i = 0; i < row; ++i) {
for (int j = 0; j < columns; ++j) {
if (grid[i][j] == '1') {
grid[i][j] = '0';
if (i - 1 >= 0 && grid[i - 1][j] == '1') uf.union(i * columns + j, (i - 1) * columns + j);
if (i + 1 < row && grid[i + 1][j] == '1') uf.union(i * columns + j, (i + 1) * columns + j);
if (j - 1 >= 0 && grid[i][j - 1] == '1') uf.union(i * columns + j, i * columns + j - 1);
if (j + 1 < columns && grid[i][j + 1] == '1') uf.union(i * columns + j, i * columns + j + 1);
}
}
}
return uf.getCount();
}
}
欢迎关注微.信公.众号一起加油吖:爱写Bug
LeetCode 200:岛屿数量 Number of Islands的更多相关文章
- Java实现 LeetCode 200 岛屿数量
200. 岛屿数量 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. ...
- 力扣Leetcode 200. 岛屿数量
岛屿数量 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量. 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成. 此外,你可以假设该网 ...
- LeetCode 200. 岛屿数量
习题地址 https://leetcode-cn.com/problems/number-of-islands/ 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水 ...
- Leetcode之深度优先搜索(DFS)专题-200. 岛屿数量(Number of Islands)
Leetcode之深度优先搜索(DFS)专题-200. 岛屿数量(Number of Islands) 深度优先搜索的解题详细介绍,点击 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计 ...
- Leetcode 200.岛屿的数量 - DFS、BFS
Leetcode 200 岛屿的数量: DFS利用函数调用栈保证了检索顺序, BFS则需要自己建立队列,把待检索对象按规则入队. class Solution { // DFS解法,8ms/10.7M ...
- [LeetCode]695. 岛屿的最大面积(DFS/BFS)、200. 岛屿数量(DFS/BFS待做/并差集待做)
695. 岛屿的最大面积 题目 给定一个包含了一些 0 和 1的非空二维数组 grid , 一个 岛屿 是由四个方向 (水平或垂直) 的 1 (代表土地) 构成的组合.你可以假设二维矩阵的四个边缘都被 ...
- Leetcode题目200.岛屿数量(BFS+DFS+并查集-中等)
题目描述: 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 ...
- Leetcode 200. 岛屿的个数(扩展)
1.题目描述 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 ...
- LeetCode 200. 岛屿的个数(Number of Islands)
题目描述 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 1 ...
随机推荐
- css的伪元素 ::after ::before 和 图标字体的使用
浅谈css的伪元素::after和::before css中的::after和::before已经被大量地使用在我们日常开发中了,使用他们可以使我们的文档结构更加简洁.但是很多人对::after和 ...
- Leetcode练习题Search Insert Position
Question: Given a sorted array and a target value, return the index if the target is found. If not, ...
- HTML+css基础 标签
图片标签:<img src="./imgs/1.jpg" alt=“一种对图片解释说明的” /> HTML 超文本标记语言 英文名称: hyper text ...
- HashMap框架源码深入解读,面试不用愁
在Java Collections Framework的体系中中,主要有两个重要的接口,一个是List.Set和Queue所属的Collection,还有一个就是Map接口了.在上一篇文章中介绍了Li ...
- 浅谈Vue下的components模板
浅谈Vue下的components模板在我们越来越深入Vue时,我们会发现我们对HTML代码的工程量会越来越少,今天我们来谈谈Vue下的 components模板的 初步使用方法与 应用 我们先来简单 ...
- PHP多进程系列笔(转)
本系列文章将向大家讲解pcntl_*系列函数,从而更深入的理解进程相关知识. PCNTL在PHP中进程控制支持默认是关闭的.您需要使用 --enable-pcntl 配置选项重新编译PHP的 CGI或 ...
- Shell—三剑客(grep、sed、awk)
grep命令详解 文本搜索工具,根据用户指定的“模式(pattern)”对目标文本进行过滤,显示被模式匹配到的行. 命令格式:grep [options] pattern filename.gr ...
- 修改postgresql 密码
sudo -u postgres psql -c "alter user postgres password '123456';"
- 系统设计与分析:Alpha版本2成绩汇总
作业要求 1.作业内容 作业具体要求以及评分标准 2.评分细则 •给出开头和团队成员列表(10’) •给出发布地址以及安装手册(20’) •给出测试报告(40’) •给出项目情况总结(30’) * ...
- HashMap了解吗?
HashCode() HashMap 底层实现 HashMap 的长度为什么默认初始长度是16,并且每次resize()的时候,长度必须是2的幂次方? HashMap 死链问题 Java 8 与 Ja ...