今天是小浩算法“365刷题计划”第102天。每个人的起点和终点都是一样的,但过程却各不相同。我们无法主宰生死却可以选择如何让生命有意义。我们如何用算法来进行一场生命的游戏呢!

01

PART

生命游戏

生命游戏,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。

给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。

每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:

  • 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;

  • 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;

  • 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;

  • 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;

根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。

题目有点复杂,举例说明:

注意:面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。

02

PART

题解分析

这道题目的关键点是:面板上所有格子需要同时被更新

本题的复杂主要复杂在 4 个更新规则,所以我们需要先对 4 个规则进行掌握(我们仅对下面绿色标出的元素进行说明)

  • R1:细胞数少于两个,则该位置活细胞死亡

  • R2:有两个或三个活细胞,则该位置活细胞仍然存活

  • R3:有超过三个活细胞,则该位置活细胞死亡

  • R4:有三个活细胞,则该位置死细胞复活

四个规则理解起来并不复杂,现在考虑如何解决问题。最自然的想法是:一个个的更新细胞状态。

但是这里我们会遇到一个问题:假设你每次更新完毕后,都把更新后的结果填入数组。那么当前轮其他格子的更新就会引用到你已经更新的结果。啥意思呢:

比如上面这个就是错误的:我们先依据规则4更新了绿色框处的状态,此时蓝色框色周围同样满足规则4。已更新细胞的状态会影响到周围其他还未更新细胞状态的计算。这明显不是我们想要的!

那我们最简单的思路:是不是只要我们能一直获取原始数组的数据,不就可以保证更新一直正确了吗!至于在哪里,其实不管是copy一个数组,还是说用hashmap存一下数值其实都ok。

因为这种思路相对比较简单,我就直接上 leetcode 官方题解的代码了:

//JAVA
class Solution {public void gameOfLife(int[][] board) {int[] neighbors = {0, 1, -1};int rows = board.length;int cols = board[0].length;// 创建复制数组 copyBoardint[][] copyBoard = new int[rows][cols];// 从原数组复制一份到 copyBoard 中for (int row = 0; row < rows; row++) {for (int col = 0; col < cols; col++) {copyBoard[row][col] = board[row][col];}}// 遍历面板每一个格子里的细胞for (int row = 0; row < rows; row++) {for (int col = 0; col < cols; col++) {// 对于每一个细胞统计其八个相邻位置里的活细胞数量int liveNeighbors = 0;for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++) {if (!(neighbors[i] == 0 && neighbors[j] == 0)) {int r = (row + neighbors[i]);int c = (col + neighbors[j]);// 查看相邻的细胞是否是活细胞if ((r < rows && r >= 0) && (c < cols && c >= 0) && (copyBoard[r][c] == 1)) {liveNeighbors += 1;}}}}// 规则 1 或规则 3      if ((copyBoard[row][col] == 1) && (liveNeighbors < 2 || liveNeighbors > 3)) {board[row][col] = 0;}// 规则 4if (copyBoard[row][col] == 0 && liveNeighbors == 3) {board[row][col] = 1;}}}}
}

然后有意思的事情发生了,大神之所以是大神,就是大神的思路和普通人不一样。大神说,你这种方法可以是可以,但是占用了新的空间。

你不就想既可以保存原数组的状态,还可以更新新的状态吗?这些统统都可以在原有数组上搞。具体怎么搞呢?

  • 原来的 0 和 1 不就是代表死和生吗?但是你要更新新的状态,无非就是从生->死,从死->生。那我们加个状态 2,代表 生->死,加个状态 3 表示从 死>生。

  • 对于一个节点来说,如果它周边的点是 1 或者 2,就说明该点上一轮是活的。

  • 整体策略是完成 原始状态->过渡状态->真实状态 的过程。

  • 过渡状态 到 真实状态,代码就是把 0 和 2 变回 0,1 和 3 变回1的过程。用模只是代码技巧。

  • 策略实现的第一步是先找到当前节点周围的存活节点数。

代码大概就是这样:

//JAVA
public class Solution {public void gameOfLife(int[][] board) {int m = board.length, n = board[0].length;// 原始状态 -> 过渡状态for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){int liveNeighbors  = 0;// 判断上边if(i > 0){liveNeighbors  += board[i - 1][j] == 1 || board[i - 1][j] == 2 ? 1 : 0;}// 判断左边if(j > 0){liveNeighbors  += board[i][j - 1] == 1 || board[i][j - 1] == 2 ? 1 : 0;}// 判断下边if(i < m - 1){liveNeighbors  += board[i + 1][j] == 1 || board[i + 1][j] == 2 ? 1 : 0;}// 判断右边if(j < n - 1){liveNeighbors  += board[i][j + 1] == 1 || board[i][j + 1] == 2 ? 1 : 0;}// 判断左上角if(i > 0 && j > 0){liveNeighbors  += board[i - 1][j - 1] == 1 || board[i - 1][j - 1] == 2 ? 1 : 0;}//判断右下角if(i < m - 1 && j < n - 1){liveNeighbors  += board[i + 1][j + 1] == 1 || board[i + 1][j + 1] == 2 ? 1 : 0;}// 判断右上角if(i > 0 && j < n - 1){liveNeighbors  += board[i - 1][j + 1] == 1 || board[i - 1][j + 1] == 2 ? 1 : 0;}// 判断左下角if(i < m - 1 && j > 0){liveNeighbors  += board[i + 1][j - 1] == 1 || board[i + 1][j - 1] == 2 ? 1 : 0;}// 根据周边存活数量更新当前点,结果是 0 和 1 的情况不用更新if(board[i][j] == 0 && liveNeighbors  == 3){board[i][j] = 3;} else if(board[i][j] == 1){if(liveNeighbors  < 2 || liveNeighbors  > 3) board[i][j] = 2;}}}// 过渡状态 -> 真实状态for(int i = 0; i < m; i++){for(int j = 0; j < n; j++){board[i][j] = board[i][j] % 2;}}}
}

细心的读者也许会想到,这不就是卡诺图吗?是的。在大多数的矩阵状态变化类题目中,卡诺图、状态机 等都是一些常用的技巧。

一般的通用解法为:

1、大部分都是遍历两次矩阵,第一遍引入中间值(中间状态),存储一些原矩阵不包含的额外信息。

2、通过 原始矩阵->过渡矩阵->真实矩阵 的策略,在结尾处将中间状态置成真实状态。

3、当遍历到某个位置时,需要查看它周边的位置,此时如果每一个周围的位置都手写,然后再判断是否越界,就很麻烦。一般用一个数组,保存向周边位置变化的坐标偏移值。

4、如果是 0 和 1 的状态置换,可以使用位运算来秀操作。如果涉及状态过多,考虑是否可以简化状态。

总之:这是一道相对比较经典的题目,如果大家有兴趣,大家可以练习一下 第73题 矩阵置零,也是类似的解法。

03

PART

每日算法

宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。


我要开始认认真真的写题解了~

啦啦啦啦啦啦

嘿吼!

和大家唠唠关于图的基础知识(一)

漫画:六九式是一道简单有趣的算法题(开车...)

漫画:常考的荷兰国旗问题你还不会吗?(初级)

如果你问我对学习算法有什么建议,这篇文章是必看的:

漫画:小白为了面试如何刷题?(呕心沥血算法指导篇)

漫画:呕心泣血算法指导篇(真正的干货,怒怼那些说算法没用的人)

 小浩算法,每日

关注领取《图解算法题》高清版

进群的小伙伴请加右侧私人微信(备注:进群

漫画:生命游戏(头条、Google 面试题)相关推荐

  1. 生命游戏代码_生命游戏 the Game of Life

    引言 群居性昆虫是一个生命,鱼群.鸟群是一个生命,社会.城市是一个有机体,人类的语言是活的,人类的集体行为也是活的.这些复杂系统是如何设计出来的?世界上最著名的游戏之一,Game of Life生命游 ...

  2. 康威生命游戏是如何搭建计算机的?

    2020年4月,数学家约翰·康威(John H. Conway)因新冠肺炎去世.大家回顾康威教授平生贡献时,不可避免要提到伟大.深刻的"康威生命游戏"(Conway's Game ...

  3. 开源生态学初探——从生命游戏开始

    缘起 在最近一次开源社的理事会上,我们聊到了关于如何孵化开源项目,如何更好地帮助开源项目发展的事情.我在会后思考了很多,因此决定写一篇文章来阐述一下自己的观点. 生命游戏 首先还是想介绍一下,已经有很 ...

  4. 打造卓越游戏 | 2023 Google 游戏开发者峰会

    一款游戏从初始构想的开发到辉煌赛季的策划,开发者们每时每刻都在倾注心血潜心钻研,Google 也致力于在整个开发和发布生命周期中为您提供帮助.我们很高兴能在今年如约而至的 Google 游戏开发者峰会 ...

  5. 自我复制、风行机械兽与生命游戏:下一个伟大的事情会是非常小的

    本报道整理自CA Technologies API学院API架构主管Mike Amundsen在2014年ArchSummit大会北京站的主题演讲分享:<冯诺依曼等技术先贤留下的API规模经济启 ...

  6. 华院计算 | 他自己的生命游戏结束了,留给后人的数学游戏长存

    [一] 让我们从一个简单的游戏开始. 在一个很大(理论上无穷大)的围棋棋盘上,让黑子代表"生"而空格(称为白子)代表"死".在棋盘上的任何9个格子组成的正方形区 ...

  7. 伍六七带你学算法 进阶篇-生命游戏

    有趣的算法题–生命游戏 难度-中等 根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机. 想要体验生命游戏的小伙伴可以到这里-->生命游戏 进入 ...

  8. html5 生存游戏,html5版生命游戏

    html5版生命游戏 只有一个.html文件,无任何依赖. 使用canvas 1.[文件] index.html ~ 4KB     下载(206) canvas { background: #eee ...

  9. 生命游戏(Game of Life)描述

    一.生命游戏(Game of Life)描述 生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机,它包括一个二维矩形世界,这个世界中的每个方格居住着一个活着的或死亡的细胞.一个细胞在下一 ...

最新文章

  1. ssh 远程登陆异常SSH_EXCHANGE_IDENTIFICATION及解决过程
  2. [JLOI2014]聪明的燕姿(搜索)
  3. Spring Cloud Feign 熔断器支持
  4. WWW软件全球使用排名
  5. 周末项目:使用scikit-learn进行手语和静态手势识别
  6. Mr.J--JS事件监听(捕获冒泡)
  7. python异常处理_Python 工匠: 异常处理的三个好习惯
  8. 架构师需要了解的知识
  9. python机器学习之物体识别
  10. 太阳代理ip_IP直通车 | 冬季之始,你知多少
  11. SPSS读取数据出现中文字符显示乱码的解决方案
  12. 前端屏幕尺寸和分辨率_移动端尺寸基础知识
  13. Python|美国婴儿姓名分析
  14. 暑假规划及小学期总结
  15. Python系列英文原版电子书
  16. 拒绝调包 手写实现神经网络(复习专用)
  17. 《信息物理融合系统(CPS)设计、建模与仿真——基于 Ptolemy II 平台》——1.7 时间模型...
  18. python打印商品列表_python 列表应用-简单的购物车
  19. Centos 7安装Gnome图形界面
  20. 孙正义:未来30年的人工智能和物联网

热门文章

  1. Linux高级课程----Linux的例行性工作和chrony服务器
  2. 网页上facebook分享功能的具体实现
  3. 矩阵的翻转与旋转()(另附代码)
  4. python多线程应用
  5. 高速光耦(PS8101,TLP112A,TLP109)基本工作原理应用实例
  6. 上海计算机5年制大专学校,上海五年制大专学校排名
  7. 高数-不定积分--凑积分(第一类换元法)
  8. 企业运维实战--lvs之DR模式负载均衡、keepalived、lvs高可用
  9. 2021-2027全球及中国G Suite教学资源软件行业研究及十四五规划分析报告
  10. 可控硅为啥不能用万用表触发?可控硅四种工作象限分析