leetcode 200. 岛屿数量

225 阅读1分钟

力扣题目链接
牛客题目链接

思路有二

  • 深度优先搜索(depth first search,简称DFS)
  • 广度优先搜索(breadth first search,简称BFS),又叫宽度优先搜索

解法一

深度优先搜索基于栈。

之所以将结构类型命名为Earth是因为如果命名为NodePoint可能和做题网站的内部常用类型名冲突。

注意Earth中的IJ,根据矩阵的行列个数对它们的类型做了优化,没有使用int
行和列个数都在200以内(牛客 <=200),可以用uint8
行和列个数都在300以内(力扣 <=300),可以用uint16

import "container/list"

func numIslands(grid [][]byte) int {
    var c int // 记录岛屿个数
    for i, row := range grid {
        for j, n := range row {
            if n == '1' {
                c++ // 每次dfs都加1
                dfs(grid, i, j)
            }
        }
    }
    return c
}

type Earth struct {
    I uint16 // row
    J uint16 // col
}

// 深度优先搜索
// 每次调用dfs,将格子grid[i][j]周围连通的一片'1'都找到了
func dfs(grid [][]byte, i, j int) {
    rows := uint16(len(grid))
    cols := uint16(len(grid[0]))
    sk := NewStack()
    sk.Push(Earth{I:uint16(i), J:uint16(j)})
    grid[i][j] = '0' // 置'0'就相当于记录该格子已经访问过了
    for !sk.IsEmpty() {
        p := sk.Peek().(Earth)
        sk.Pop()
        // right
        if p.J+1 < cols && grid[p.I][p.J+1] == '1' { // 如果没访问过,就加入搜索集
            sk.Push(Earth{I:uint16(p.I), J:uint16(p.J+1)})
            grid[p.I][p.J+1] = '0'
        }
        // left
        if p.J >= 1 && grid[p.I][p.J-1] == '1' {
            sk.Push(Earth{I:uint16(p.I), J:uint16(p.J-1)})
            grid[p.I][p.J-1] = '0'
        }
        // up
        if p.I >= 1 && grid[p.I-1][p.J] == '1' {
            sk.Push(Earth{I:uint16(p.I)-1, J:uint16(p.J)})
            grid[p.I-1][p.J] = '0'
        }
        // down
        if p.I+1 < rows && grid[p.I+1][p.J] == '1' {
            sk.Push(Earth{I:uint16(p.I)+1, J:uint16(p.J)})
            grid[p.I+1][p.J] = '0'
        }
    }
}

// 栈实现
type Stack struct {
	l *list.List
}

func NewStack() *Stack {
	return &Stack{
		l: list.New(),
	}
}

func (o *Stack) Push(v interface{}) {
	o.l.PushBack(v)
}

func (o *Stack) Peek() interface{} {
	if o.IsEmpty() {
		panic("Stack is empty")
	}
	return o.l.Back().Value
}

func (o *Stack) Pop() {
	if o.IsEmpty() {
		panic("Stack is empty")
	}
	o.l.Remove(o.l.Back())
}

func (o *Stack) IsEmpty() bool {
	return o.l.Len() == 0
}

func (o *Stack) Len() int {
	return o.l.Len()
}

解法二

广度优先搜索基于队列。

func numIslands(grid [][]byte) int {
    var c int // 记录岛屿个数
    for i, row := range grid {
        for j, n := range row {
            if n == '1' {
                c++ // 每次搜索加1
                bfs(grid, i, j)
            }
        }
    }
    return c
}

type Earth struct {
    I uint16 // row
    J uint16 // col
}

// 广度优先搜索
// 每次调用bfs,将格子grid[i][j]周围连通的一片'1'都找到了
func bfs(grid [][]byte, i, j int) {
    rows := uint16(len(grid))
    cols := uint16(len(grid[0]))
    q := NewQueue()
    q.Push(Earth{I:uint16(i), J:uint16(j)})
    grid[i][j] = '0' // 标记格子已访问过
    for !q.IsEmpty() {
        p := q.Pop().(Earth)
        // right
        if p.J+1 < cols && grid[p.I][p.J+1] == '1' { // 如果没访问过,就加入搜索集
            q.Push(Earth{I:uint16(p.I), J:uint16(p.J+1)})
            grid[p.I][p.J+1] = '0'
        }
        // left
        if p.J >= 1 && grid[p.I][p.J-1] == '1' {
            q.Push(Earth{I:uint16(p.I), J:uint16(p.J-1)})
            grid[p.I][p.J-1] = '0'
        }
        // up
        if p.I >= 1 && grid[p.I-1][p.J] == '1' {
            q.Push(Earth{I:uint16(p.I-1), J:uint16(p.J)})
            grid[p.I-1][p.J] = '0'
        }
        // down
        if p.I+1 < rows && grid[p.I+1][p.J] == '1' {
            q.Push(Earth{I:uint16(p.I+1), J:uint16(p.J)})
            grid[p.I+1][p.J] = '0'
        }
    }
}

// 队列实现
type Queue struct {
	l *list.List
}

func NewQueue() *Queue {
	return &Queue{
		l: list.New(),
	}
}

func (o *Queue) Push(v interface{}) {
	o.l.PushBack(v)
}

func (o *Queue) Pop() interface{} {
	if o.IsEmpty() {
		panic("Queue is empty")
	}
	e := o.l.Front()
	o.l.Remove(e)
	return e.Value
}

func (o *Queue) Front() interface{} {
	if o.IsEmpty() {
		panic("Queue is empty")
	}
	return o.l.Front().Value
}

func (o *Queue) Back() interface{} {
	if o.IsEmpty() {
		panic("Queue is empty")
	}
	return o.l.Back().Value
}

func (o *Queue) IsEmpty() bool {
	return o.l.Len() == 0
}

func (o *Queue) Len() int {
	return o.l.Len()
}