题目描述:
根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。
示例:
输入:
输出:
进阶:
你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
思路:
两种思路,一种额外申请数组空间,一种直接利用原数组。
下面讲解第二种思路:
由题可知,更新是同时进行的,所以必须保留原状态。
因为数组中存储的只有0和1两个数字,所以二进制中只用到最后一位,我们可以利用其它二进制位。
所以产生如下定义:
0b00 原来状态是0,更新后状态也是0;0b10 原来状态是0,更新后状态也是1;
0b01 原来状态是1,更新后状态也是0;0b11 原来状态是1,更新后状态也是1;
根据最后一位二进制位来判断周边位置1的个数,根据生存定律来更新其状态,即前一位二进制。
最后将数组中数右移一位,即可得到更新之后的状态。
class Solution {
publi
int DX[8]={0,0,1,-1,1,1,-1,-1};//下,上,右,左,右下,右上,左下,左上
int DY[8]={1,-1,0,0,1,-1,1,-1};
void gameOfLife(vector<vector<int>>& board) {
int m=board.size();
if(m==0) return;
int n=board[0].size();
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
int count=0;
for(int k=0;k<8;k++){//查找周边八个位置
int x=i+DX[k];
int y=j+DY[k];
if(x<0||x>=m||y<0||y>=n)//不在矩阵内,继续
continue;
count += board[x][y]&1;//查找周边1的个数,&1是因为周边位置可能前一位已有新的状态
}
if((board[i][j]&1)>0){
if(count==2||count==3){
board[i][j]=3;//3的二进制位0b11,最后一位为之前状态,前一位为现在状态
}
}
else{
if(count==3){
board[i][j]=2;//2的二进制位0b10,最后一位为之前状态,前一位为现在状态
}
}
}
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
board[i][j] >>=1;//右移一位,全部转换为当前状态
}
}
}
};