go面试题 腐烂的苹果(橘子、水果)

本文介绍了一种模拟腐烂苹果如何在网格中扩散的算法问题。通过两种方法——广度优先搜索(BFS)和队列实现,来解决网格中所有好苹果最终腐烂所需的时间。若存在无法腐烂的好苹果,则返回-1。

题目:给定一个n \times m的网格,其中每个单元格中可能有三种值。分别是0,1,2。

0表示这个格子为空,1表示这个格子有一个完好的苹果,2表示这个格子有一个腐烂的苹果。

腐烂的苹果每分钟会向上下左右四个方向的苹果传播一次病菌,并导致相邻的苹果腐烂。请问经过多少分钟,网格中不存在完好的苹果。如果有苹果永远不会腐烂则返回-1。

数据范围:1 \leq n , m \leq 100 , 网络中的值满足0  \leq  val  \leq 2

 测试用例:

用例1
输入:[[2,1,1],[1,1,0],[0,1,1]]
输出:4

用例2
输入:[[2,1,1],[1,0,1],[1,1,1]]
输出:4

 题目评价:

本人是最讨厌这种类型的题目,感觉特别麻烦(本人太菜了)。但这种题目的主流解法有两种:广度优先搜索(BFS)和 队列实现

解题思路:

方法一(BFS):

首先分别将腐烂的橘子和新鲜的橘子保存在两个集合中;

模拟广度优先搜索的过程,方法是判断在每个腐烂橘子的四个方向上是否有新鲜橘子,如果有就腐烂它。每腐烂一次时间加 11,并剔除新鲜集合里腐烂的橘子;

当橘子全部腐烂时结束循环。

func orangesRotting(grid [][]int) int {
	if !hasFresh(grid) {
		return 0
	}

	time := getTimes(grid)

	if hasFresh(grid) {
		return -1
	}
	return time
}

func hasFresh(grid [][]int) bool {
	for i := range grid {
		for _, val := range grid[i] {
			if 1 == val {
				return true
			}
		}
	}
	return false
}

func getTimes(grid [][]int) int {
	q := getQueue(grid)
	time := 0

	for len(q) > 0 {
		next := make([][]int, 0)

		for i := range q {
			row := q[i][0]
			col := q[i][1]

			next = setRot(grid, next, row-1, col)
			next = setRot(grid, next, row, col+1)
			next = setRot(grid, next, row+1, col)
			next = setRot(grid, next, row, col-1)
		}

		if len(next) != 0 {
			time++
		}
		q = next
	}
	return time
}

func getQueue(grid [][]int) [][]int {
	q := make([][]int, 0)
	for i := range grid {
		for j, val := range grid[i] {
			if 2 == val {
				q = append(q, []int{i, j})
			}
		}
	}
	return q
}

func setRot(grid, q [][]int, row, col int) [][]int {
	if row < 0 || col < 0 || row >= len(grid) || col >= len(grid[0]) || grid[row][col] != 1 {
		return q
	}
	grid[row][col] = 2
	q = append(q, []int{row, col})
	return q
}

方法二( 队列实现):

// 位置结构体
type Pos struct {r,c int}

// 队列
type Queue []Pos

// 入队
func (this *Queue)Push(x Pos) {
    (*this) = append(*this,x)
}

// 出队
func (this *Queue)Pop() Pos {
    res := (*this)[0]
    (*this) = (*this)[1:len(*this)]
    return res
}

// 判断队空
func (this Queue)IsEmpty() bool {
    if len(this) == 0 {return true}
    return false
}

func orangesRotting(grid [][]int) int {
    res := -1
    n,m := len(grid),len(grid[0])
    dir := [][2]int{{1,0},{-1,0},{0,1},{0,-1}}  // 方向矢量
    num1,num2 := 0,0    // 记录每一层腐烂橘子的数目
    flag := false   // 记录初始状态下是否含有新鲜橘子
    var ql Queue
    for i := 0; i < n; i++ {
        for j := 0; j < m; j++ {
            if grid[i][j] == 2 {    // 把第一层腐烂橘子入队并计数
                ql.Push(Pos{i,j})
                num1++
            }
            if grid[i][j] == 1 {flag = true}
        }
    }
    if num1 == 0 {  // 若没有腐烂的橘子结果取决于有无新鲜的橘子
        if flag {return -1}
        return 0
    }
    for !ql.IsEmpty() {
        now := ql.Pop()
        for i := 0; i < 4; i++ {
            r,c := now.r+dir[i][0],now.c+dir[i][1]
            if r >= 0 && r < n && c >= 0 && c < m && grid[r][c] == 1 {
                grid[r][c] = 2
                ql.Push(Pos{r,c})
                num2++
            }
        }
        num1--
        if num1 == 0 {  // 遍历完一层就记一次数
            res++
            num1 = num2
            num2 = 0
        } 
    }
    // 判断是否还有新鲜的橘子
    for i := 0; i < n; i++ {
        for j := 0; j < m; j++ {
            if grid[i][j] == 1 {return -1}
        }
    }
    return res
}

如果还是看不懂,可以看这个力扣网站上面的这道题目,相信对你有所帮助力扣icon-default.png?t=M85Bhttps://leetcode.cn/problems/rotting-oranges/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值