根据百度百科,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在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] ]
进阶:
- 你可以使用原地算法解决本题吗?请注意,面板上所有格子需要同时被更新:你不能先更新某些格子,然后使用它们的更新后的值再更新其他格子。
- 本题中,我们使用二维数组来表示面板。原则上,面板是无限的,但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题?
思路:
要求是使用原地算法,所以新开一个数组进行计算的方法就不考虑了。
因此,我们要将board[i][j]改变之前和改变之后的状态记录下来。可以发现一共有4种情况:
- 0 -> 0
- 1 -> 1
- 0 -> 1
- 1 -> 0
前两种情况没有发生状态的改变,可以不管。对于后两种情况,0->1时,可将board[i][j]=2,1->0时,将board[i][j]=3,这样就可以知道board[i][j]改变之前和改变之后的状态了。最后再将状态2、3改回对应的1、2状态即可。
class Solution {
int[] dx= new int[]{-1,0,1};
int[] dy= new int[]{-1,0,1};
int m,n;
boolean check(int x,int y,int[][] board){
int cnt=0;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
if(dx[i]==0&&dy[j]==0)continue;
int nx=x+dx[i];
int ny=y+dy[j];
if(nx<0||nx>=m||ny<0||ny>=n) continue;
if(board[nx][ny]==1||board[nx][ny]==3)cnt++;
}
}
if(board[x][y]==1&&(cnt<2||cnt>3)) return true;
if(board[x][y]==0&&cnt==3)return true;
return false;
}
public void gameOfLife(int[][] board) {
m=board.length;
n=board[0].length;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(check(i,j,board)){
board[i][j]+=2;
}
}
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(board[i][j]==2)board[i][j]=1;
if(board[i][j]==3)board[i][j]=0;
}
}
}
}