LeetCode 75 —— 200. 岛屿数量

90 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情

LeetCode 75 —— 200. 岛屿数量

一、题目描述:

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid =

[ ["1","1","1","1","0"],

["1","1","0","1","0"],

["1","1","0","0","0"],

["0","0","0","0","0"] ]

输出:1

示例 2:

输入:grid = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ]

输出:3

提示:

m == grid.length

n == grid[i].length

1 <= m, n <= 300

grid[i][j] 的值为 '0' 或 '1'

来源:力扣(LeetCode)

链接:leetcode.cn/problems/nu…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、思路分析:

  1. 这道题考察了什么思想?你的思路是什么?

    对于这种岛屿问题,我们上次也讲了,可以使用DFS模板。对于网格上的DFS,首先我们要知道坐标为(r,c)的格子,其相邻的格子分别是:(r-1, c)(r+1, c)(r, c-1)(r, c+1)。然后我们就要确定递归终止条件,也就是判断坐标(r,c)是否在网格之中,也就是r<0 || c<0 || r>=len(grid) || c>=len(grid[0])。接下来需要注意的是,如何避免重复遍历,我们在图中遍历时,不可避免会遍历到重复的节点,因此需要将遍历过的节点做一个标记。于是我们将'1'赋值为'x'即可。

  2. 做题的时候是不是一次通过的,遇到了什么问题,需要注意什么细节?

    不是啊。

    如果照上面的思路,就会产生一个问题:

image.png

问题出现在哪呢?

如果将遍历过的节点设置为'x',就可能会导致r<0 || c<0 || r>=len(grid) || c>=len(grid[0]) || grid[r][c] == '0'一个条件都达不到,我们应该设置为以下r<0 || c<0 || r>=len(grid) || c>=len(grid[0]) || grid[r][c] != '1' {

    func numIslands(grid [][]byte) int {
        result := 0
        for i:=0; i<len(grid); i++{
            for j:=0; j<len(grid[i]); j++{
                if grid[i][j] == '1' {
                    result++
                    helper(grid,i,j)
                }
            }
        }
        return result
    }
    ​
    func helper(grid [][]byte,r,c int) {
        if r<0 || c<0 || r>=len(grid) || c>=len(grid[0]) || grid[r][c] != '1' {
            return
        }
        
        grid[r][c] = 'x'
        helper(grid,r-1,c)
        helper(grid,r,c-1)
        helper(grid,r,c+1)
        helper(grid,r+1,c)
    }
    ​
  1. 有几种解法,哪种解法时间复杂度最低,哪种解法空间复杂度最低,最优解法是什么?其他人的题解是什么,谁的效率更好一些?用不同语言实现的话,哪个语言速度最快?

    使用并查集实现:

    type UnionFindSet struct {
        Parents []int // 每个结点的顶级节点
        SetCount int // 连通分量的个数
    }
    ​
    func (u *UnionFindSet) Init(grid [][]byte) {
        row := len(grid)
        col := len(grid[0])
        count := row*col
        u.Parents = make([]int, count)
        for i := 0; i < row; i++ {
            for j := 0; j < col; j++ {
                u.Parents[i*col+j] = i*col+j
                if grid[i][j] == '1' {
                    u.SetCount++
                }
            }
        }
    }
    ​
    func (u *UnionFindSet) Find(node int) int {
        if u.Parents[node] == node {
            return node
        }
        root := u.Find(u.Parents[node])
        u.Parents[node] = root
        return root
    }
    ​
    func (u *UnionFindSet) Union(node1 int, node2 int) {
        root1 := u.Find(node1)
        root2 := u.Find(node2)
        if root1 == root2 {
            return
        }
        if root1 < root2 {
            u.Parents[root1] = root2
        } else {
            u.Parents[root2] = root1
        }
        u.SetCount--
    }
    // 心得:并查集是一种搜索算法(针对聚合的)
    func numIslands(grid [][]byte) int {
        // 创建并初始化并查集
        u := &UnionFindSet{}
        row := len(grid)
        col := len(grid[0])
        u.Init(grid)
        // 根据grid建立相应的并查集,并统计连通分量个数【每连接一次进行减一】
        for i := 0; i < row; i++ {
            for j := 0; j < col; j++ {
                if grid[i][j] == '1' {
                    // 如果周边四个方向也是1就进行union
                    if i - 1 >= 0 && grid[i-1][j] == '1' {
                        u.Union(i*col+j, (i-1)*col+j)
                    }
                    if i + 1 < row && grid[i+1][j] == '1' {
                        u.Union(i*col+j, (i+1)*col+j)
                    }
                    if j - 1 >= 0 && grid[i][j-1] == '1' {
                        u.Union(i*col+j, i*col+(j-1))
                    }
                    if j + 1 < col && grid[i][j+1] == '1' {
                        u.Union(i*col+j, i*col+(j+1))
                    }
                    grid[i][j] = '0'
                }
            }
        }
        // 返回结果
        return u.SetCount
    }
    ​
    作者:bryson-2
    链接:https://leetcode.cn/problems/number-of-islands/solution/bing-cha-ji-go-by-bryson-2/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

三、AC 代码:

func numIslands(grid [][]byte) int {
 result := 0
 for i:=0; i<len(grid); i++{
     for j:=0; j<len(grid[i]); j++{
         if grid[i][j] == '1' {
             result++
             helper(grid,i,j)
         }
     }
 }
 return result
}
​
func helper(grid [][]byte,r,c int) {
 if r<0 || c<0 || r>=len(grid) || c>=len(grid[0]) || grid[r][c] == '0' {
     return
 }
​
 grid[r][c] = '0'
 helper(grid,r-1,c)
 helper(grid,r,c-1)
 helper(grid,r,c+1)
 helper(grid,r+1,c)
}
​

四、总结:

深度优先搜索的时间复杂度和空间复杂度都为O(NM),其中 M*M 和 N*N 分别为行数和列数。

模板来源:

作者:掘金酱

链接:juejin.cn/post/706970…

来源:稀土掘金

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。