[LeetCode-Golang] 289. 生命游戏
题目
根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/game-of-life
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
直接遍历数组,根据条件修改状态即可。
只需要注意两点
1.可以将周围的8个位置的偏移量用二维数组列出,然后循环获取周围的位置,也方便进行数组越界检查。
2.在遍历细胞数组的时候,如果直接更改某个位置的状态,会导致后面的位置错误判断活细胞个数。因此可以复制数组;也可以在原数组中用没有出现过的状态值来进行修改,再遍历一遍数组替换为0或1。
代码
func gameOfLife(board [][]int) { if board == nil || len(board) == 0 { return } // 8个方向的偏移量 offset := [][]int {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}} // 数组的行数和列数 row, col := len(board), len(board[0]) /* 根据题意下一个状态是当前状态下的细胞同时更新,所以不能直接在原数组修改细胞状态为0或1。 可以复制数组(切片),遍历原数组,而在复制的数组中修改状态,返回复制的数组,但要开辟额外空间。 注意到数组是int类型,第一次遍历在原数组中用其他数字代表状态的变化,然后第二次遍历还原成0,1。 这里将由0->1的位置改为2,将由1->0的位置改为-1。 */ // 遍历数组 for i := 0; i < row; i++ { for j := 0; j < col; j++ { // 记录当前位置相邻的活细胞数量 liveCnt := 0 // 遍历相邻细胞 for k := 0; k < 8; k++ { currX, currY := i + offset[k][0], j + offset[k][1] // 检查数组越界 if currX >= 0 && currX < row && currY >= 0 && currY < col { // 检查细胞状态(值为-1和1的位置在更新前都是活细胞) if board[currX][currY] == 1 || board[currX][currY] == -1 { liveCnt++ } } } // 判断当前细胞状态,并根据生存定律修改 if board[i][j] == 1 { // 活细胞周围的活细胞数量<2或>3,则活细胞死亡 if liveCnt < 2 || liveCnt > 3 { board[i][j] = -1 } } else if liveCnt == 3{ // 死细胞周围活细胞数量==3,则死细胞复活 board[i][j] = 2 } } } // 第二次遍历数组,将-1变成0,2变成1 for i := 0; i < row; i++ { for j := 0; j < col; j++ { if board[i][j] == -1 { board[i][j] = 0 } else if board[i][j] == 2 { board[i][j] = 1 } } } }
复杂度分析
时间复杂度:O(mn)
空间复杂度:O(1)
执行结果
执行用时 :0 ms, 在所有 Go 提交中击败了100.00% 的用户
内存消耗 :2 MB, 在所有 Go 提交中击败了100.00%的用户