Leetcode 200.岛屿数量

Time: 20190902
Type: Medium

题目描述

给定一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:

11110
11010
11000
00000

输出: 1

示例 2:

输入:

11000
11000
00100
00011

输出: 3

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-islands
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

DFS解法

和之前的一道题,LeetCode 130被包围的区域是一样的类型。也是从某一个元素出发,找连通的,一直到不连通为止。本题可以从字符1开始DFS,上下左右探索,直到下一个元素非1为止,能被探索到的,一定是相邻的元素有1,只有这样才能过来到当前位置。

并查集解法

标准的,定义并查集的类,然后实例化一个并查集对象,Union后统计大哥的数量。

代码

DFS解法

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        if grid == None or len(grid) == 0:
            return 0
        
        def dfs(grid, i, j):
            row = len(grid)
            col = len(grid[0])
            
            if i < 0 or i >= row or j < 0 or j >= col or grid[i][j] != '1': # 停止探索
                return 
            grid[i][j] = 0 # 将探索到的1置为0
            
            # 上下左右探索
            dfs(grid, i - 1, j)
            dfs(grid, i, j - 1)
            dfs(grid, i + 1, j)
            dfs(grid, i, j + 1)
            
        count = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == '1':
                    dfs(grid, i, j)
                    count += 1
        return count

结合代码来看,就是从’1’出发,开始DFS,相邻的’1’都被置为’0’,在主函数中,遇到字符1开始DFS,抓住岛屿的一角,就能一网打尽。

注意DFS的遍历过程和130非常相似,递归出口都是在不能再前进(非1,不相连)为止。

骨架是相同的,具体的细节要根据具体问题具体分析。

并查集解法

# 写好工具,要根据题意,相应的用上去
class UnionFind:
    def __init__(self, nums):
        self.pre = list(range(nums))
        
    def find(self, x):
        if self.pre[x] != x:
            self.pre[x] = self.find(self.pre[x])
        return self.pre[x]
    
    # 单独抽出一只路径压缩
    def compact(self):
        for x in range(len(self.pre)):
            r = x
            while self.pre[r] != r:
                r = self.pre[r]
                i = x
                while i != r:
                    tmp = self.pre[i]
                    self.pre[i] = r
                    i = tmp
    
    def union(self, x, y):
        xr, yr = self.find(x), self.find(y)
        self.pre[yr] = xr
        
    def getCount(self):
        self.compact()
        count = 0
        seen = set()
        for num in self.pre:
            if num not in seen:
                count += 1
                seen.add(num)
        # for i in range(len(self.pre)):
        #     if i == self.pre[i]:
        #         count += 1
        return count
    
class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:
        if not grid or len(grid) == 0:
            return 0
        row = len(grid)
        col = len(grid[0])
        
        # 二维转1维, 0表示水,[1~col * row]表示方格子中的点
        uf = UnionFind(row * col + 1)
        for i in range(row):
            for j in range(col):
                if grid[i][j] == '0':
                    uf.union(0, i * col + j + 1)
                elif grid[i][j] == '1':
                    new_x = i + 1
                    new_y = j + 1
                    if new_x < row and grid[new_x][j] == '1':
                        uf.union(i * col + j + 1, new_x * col + j + 1)
                    if new_y < col and grid[i][new_y] == '1':
                        uf.union(i * col + j + 1, i * col + new_y + 1)
                        
        return uf.getCount() - 1     

只需要右、下两个方向合并即可。

注意这种做法,最后得到的数字都是大哥,但是有些命名是一组,但大哥不统一,因为没有完全路径压缩,所以判断方式用 i == pre[i],或者再额外路径压缩一次后,统计带头大哥的数量。

相似问题

Leetcode 305.岛屿数量II
Leetcode 286.墙与门
Leetcode 323.无相图中连通分量的数目
Leetcode 694.不同岛屿的数量
Leetcode 695.岛屿的最大面积

END.

你可能感兴趣的:(LeetCode)