今天是“耶稣受难人”,笔者给自己放了天假hhh
且慢,还是会写一点的。
根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
题型:矩阵、原地实现、位运算
链接:289. 生命游戏 - 力扣(LeetCode)
来源:LeetCode
题目描述
给定一个包含 m × n
个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1
即为 活细胞 (live),或 0
即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
规则才是重点!
- 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
- 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
- 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
- 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n
网格面板 board
的当前状态,返回下一个状态。
请配合样例食用
题目样例
示例 1:
输入:board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出:[[0,0,0],[1,0,1],[0,1,1],[0,1,0]]
示例 2:
输入:board = [[1,1],[1,0]] 输出:[[1,1],[1,1]]
提示:
m == board.length
n == board[i].length
1 <= m, n <= 25
board[i][j]
为0
或1(非常人性化的矩阵设计,给了许多可能)
进阶:
- 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
- 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
题目思路
一个理解起来不难,但可能实现起来比较麻烦的矩阵模拟题。
抛开要求的【原地】不谈外,用一个新的二维数组辅助,在遍历也感觉很麻烦,外加空间复杂度直接干到了O( row * column)
那么可以考虑下题目要求的【原地】——即O(1)怎么实现。
笔者愚笨,在看了题解+评论区 2h后,才明白这套【原地+二进制表示法】。
这边先说一下,二进制(笔者只写0-3,所以2位足够)中:0是00,1是01,2是10,3是11 。
先说一下表示方法:用0表示【死细胞】状态,1表示【活细胞】状态。涉及两位数,那么【01】就是【由活向死】,【10】就是【由死向活】。那么如何实现这个状态的转化呢?这边就要用到二进制的【右移】操作(推荐自己在纸上写一下)。描述的话:假设数字的右边是个悬崖,有碾压墙把数字右推。数字右移1位,那么最右边那个就‘消失’了,【10】也就变成了【01】。
说完这个二进制表示状态的思路后,剩下的就是【原地】。这边原地笔者是先遍历【第一行】和【第一列】,确定他们会不会转化为【全0】(后面单独处理就好)。之后抛开这一行一列,遍历剩下的矩阵,按照规则找到每个点的【活细胞数】,进而确定状态。
最后通过右移操作,将矩阵更新为新的【0-1矩阵】
C++代码
class Solution {int rowLen,columnLen;
public: void gameOfLife(vector<vector<int>>& board) {// 评论区双位表示细胞状态// 00 : 第一位表示未来 ,第二位表示现在。现在 -> 未来 右移一位。rowLen = board.size();columnLen = board[0].size();int life;for(int i=0;i<rowLen;i++){for(int j=0;j<columnLen;j++){life = getLife(i,j,board);//获取周围有几个活细胞// cout<<life<<endl;// 当前是活细胞if(board[i][j] == 1){if(life == 2 || life == 3)board[i][j] += 2;// 否则未来就会死,01,保持不变}else{//死细胞从 00 变成 10 if(life == 3)board[i][j] += 2;}}}for(auto &answer : board)//用引用,来改变原数组的值for(int &ans : answer ){// 全都右移1位ans = ans>>1;}}int getLife(int row, int column,vector<vector<int>> numpy){int life = 0;//不能有{0,0} 因为 board[row][column]相当于当前元素vector<vector<int>> lifeNumpy = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};//8个状态数组,为了求出周围8个细胞的状态for(int i = 0;i < 8;i++){int x = row - lifeNumpy[i][0];int y = column - lifeNumpy[i][1];if(x<0 || x>=rowLen || y<0 || y >= columnLen)//矩阵外的细胞不处理continue;//因为board的元素除了0就是1,相当于统计周围1的个数life += numpy[x][y]&1;//应该只看最末一位,因为board不断变,状态只看原来的}return life;}
};