Leetcode 289:生命游戏(最详细的解法!!!)
根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞具有一个初始状态 live(1)即为活细胞, 或 dead(0)即为死细胞。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
- 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
- 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
- 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
- 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
根据当前状态,写一个函数来计算面板上细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。
示例:
输入:
[[0,1,0],[0,0,1],[1,1,1],[0,0,0]
]
输出:
[[0,0,0],[1,0,1],[0,1,1],[0,1,0]
]
进阶:
- 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
- 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
解题思路
类似问题
Leetcode 73:矩阵置零(最详细的解法!!!)
这个问题非常有意思,有兴趣的同学可以将其做成可视化看看效果,我在后期会给出可视化代码示例。我们回到这个问题,这个问题非常简单,由于细胞的出生和死亡是同时发生的(和之前问题类似,如果遍历前面元素直接修改结果会对后面的元素造成影响),所以最简单的做法就是新建一个matrix
。
class Solution:def gameOfLife(self, board):""":type board: List[List[int]]:rtype: void Do not return anything, modify board in-place instead."""self.w, self.h = len(board[0]), len(board)mat = [[0]*self.w for _ in range(self.h)]for r in range(self.h):for c in range(self.w):mat[r][c] = board[r][c]for r in range(self.h):for c in range(self.w):lives = self._neighborsLives(mat, (r, c))if lives < 2:board[r][c] = 0if lives > 3:board[r][c] = 0if lives == 3 and not board[r][c]:board[r][c] = 1def _neighborsLives(self, board, node):count = 0neighbors = [(0, 1), (0, -1), (1, 0), (-1, 0), (-1, -1), (1, 1), (-1, 1), (1, -1)]for i, j in neighbors:if 0 <= node[0] + i < self.h and\0 <= node[1] + j < self.w:count += board[node[0]+i][node[1]+j] & 1return count
如果不是用额外空间该怎么做?我们可以通过状态转换(在之前的问题中我们已经不止一次使用这种策略了),我们知道原先通过1bit
只能记录当前是死还是活,无法记录之前的状态,如果想要记录之前的状态,我们只有增大信息的容量,增大为多少呢?2bit
就可以啦。
- die <- die 00
- die <- live 01
- live <- die 10
- live <- live 11
我们这里使用2bit
表示状态变化(current to next)。我们先遍历board
,看每个节点周围有多少个初始状态是live
,如果这个节点原先是live
并且周围的2<=lives<4
,我们知道它现在的状态应该是live->live
,也就是对应上面的编码3
。如果这个节点原先是die
并且周围是lives==3
,我们知道它现在的状态应该是die->live
,也就是对应上面的编码2
。这些都做完之后,我们在此遍历board
,将其中的2
和3
调整回来(live or die
),怎么调呢?很简单,我们注意到我们的2
和3
编码很巧妙,直接>>1
就可以得到一次游戏后的状态了。
class Solution:def gameOfLife(self, board):""":type board: List[List[int]]:rtype: void Do not return anything, modify board in-place instead."""r, c = len(board), len(board[0])neighbors = [(0, 1), (0, -1), (1, 0), (-1, 0), (-1, -1), (1, 1), (-1, 1), (1, -1)]for i in range(r):for j in range(c):lives = 0for m, n in neighbors:if 0 <= i + m < r and 0 <= j + n < c:lives += board[i+m][j+n] & 1if board[i][j] and 2 <= lives < 4:board[i][j] = 3if not board[i][j] and lives == 3:board[i][j] = 2for i in range(r):for j in range(c):board[i][j] >>= 1
要注意我们在Leetcode 73:矩阵置零(最详细的解法!!!)问题中没有采用这种增大信息量的方式,因为我们可以对问题进行全局考虑(也就是一旦输入结果确定,我们就会知道输出结果)。而这个问题按理说应该是可以通过全局考虑的,但是很麻烦,远没有通过增大信息量来解容易。那么之前那个问题应该也可以通过增大信息量来接吧?大家可以试试。
如果矩阵无限大我们该怎么办?我们希望我们存储的信息尽可能少,所以我们可以只记录存活节点的坐标,每次更新记录存活节点坐标的数组。
class Solution:def gameOfLife(self, board):""":type board: List[List[int]]:rtype: void Do not return anything, modify board in-place instead."""live = {(i, j) for i, row in enumerate(board) for j, live in enumerate(row) if live}live = self.gameOfLifeInfinite(live)for i, row in enumerate(board):for j in range(len(row)):row[j] = int((i, j) in live)def gameOfLifeInfinite(self, live):neighbors = collections.Counter()for i, j in live:for I in (i-1, i, i+1):for J in (j-1, j, j+1):if I != i or J != j:neighbors[I, J] += 1new_live = set()for key, val in neighbors.items():if val == 3 or val == 2 and key in live:new_live.add(key)return new_live
reference:
https://leetcode.com/problems/game-of-life/discuss/73223/Easiest-JAVA-solution-with-explanation
https://segmentfault.com/a/1190000003819277#articleHeader1
https://leetcode.com/problems/game-of-life/discuss/73217/Infinite-board-solution
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!
Leetcode 289:生命游戏(最详细的解法!!!)相关推荐
- 【leetcode】289.生命游戏 (三种解法开阔思路,java实现)
289. 生命游戏 难度中等 根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机. 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个 ...
- LeetCode 289. 生命游戏(位运算)
文章目录 1. 题目 2. 解题 2.1 复制数组解法 2.2 原地解法 2.3 位运算 1. 题目 链接:289. 生命游戏 2. 解题 2.1 复制数组解法 很简单,按照题意模拟即可 class ...
- LeetCode 289. 生命游戏
289. 生命游戏 思路:数每个格子周围Cell存活数 笔记:vector复制 vector<vector<int> > tmp(board); class Solution ...
- [leetcode][289. 生命游戏]
根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机. 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞.每个细胞具有一个初始状态 liv ...
- c语言 细胞自动机,Leetcode 289. 生命游戏 (细胞自动机)
二维网格遍历注意使用技巧让代码可读性强. 原始的思路是使用一个二维数组进行更新,当全部更新完以后,复制这个二维数组到原来的数组上. 可不可以优化,不使用额外的空间,答案是可以的 细胞的状态如下: ...
- LeetCode 0289. 生命游戏
[LetMeFly]289.生命游戏 力扣题目链接:https://leetcode.cn/problems/game-of-life/ 根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约 ...
- LeetCode 45.跳跃游戏② (超详细)
给你一个非负整数数组 nums ,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 你的目标是使用最少的跳跃次数到达数组的最后一个位置. 假设你总是可以到达数组的最后一 ...
- C语言零基础项目:生命游戏!详细思路+源码分享
每天一个C语言小项目,提升你的编程能力! 程序简介 生命游戏也叫康威生命游戏.细胞自动机.元胞自动机等. 生命游戏不需要任何玩家,它是一个二维矩形世界,这个世界中的每个方格居住着一个活细胞或为空. 一 ...
- 289. 生命游戏。
根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机. 给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞.每个细胞都具有一 ...
- leetcode 289. Game of Life | 289. 生命游戏(Java)
题目 https://leetcode.com/problems/game-of-life/ 题解 首先,遍历整个棋盘,如果是 1,就将上下左右的 count 值加 1. 然后,没有任何技巧,就是根据 ...
最新文章
- 百度认为什么样的网站更有抓取和收录价值
- 网络营销——网络营销专员表明网站地图助力网站收录进一步提升
- IPFS + 区块链 系列】 入门篇 - IPFS + Ethereum (中篇)-js-ipfs-api - 图片上传到IPFS以及下载
- 笔记2深度学习 梯度和梯度法
- 系统测试分类和测试常用方法
- MySQL基础课堂笔记
- 重写setTimeout扩展参数
- 如何判断当前请求的是健康检查API
- Linux文件属性及如何修改文件属性
- sizeof与strlen使用中的问题
- linux中如何复制文件并重命名_linux 下怎么复制一个文件到另外一个目录并且重命名...
- java xml解析_Java解析XML(4种方法)
- Unity3D - UGUI组件的中英文对照
- 新手填坑 java.lang.Integer cannot be cast to java.lang.String
- Julia: save 与 @save
- 云南省湖泊河流ArcGIS地形图shp图层文件下载
- 2020神舟几号发射_今年将发射神舟十一号载人飞船 2020年将建成载人空间站
- 伺服电机的工作原理是什么
- C++学习(一七八)Android的arm64-v8a、armeabi-v7a、armeabi、x86
- 文献跟踪、文献订阅工具
热门文章
- IDS相机SDK二次开发
- 网络之路由器工作原理
- 图解Janusgraph系列-并发安全,醍醐灌顶!
- 基于云原生的边缘计算在大麦现场的探索应用
- python学习笔记-马哥2017
- 2017年web前端职位_2017年最热门的5大IT职位
- 邮件中html内嵌图片,email - 在HTML电子邮件中嵌入附加图像 - SO中文参考 - www.soinside.com...
- db后缀的文件导出为excel
- 美味しい!一份日式料理是如何“炼”成的?
- python字符串的定界符不能是_Python|字符串str的构造、操作(操作符、函数、方法)...