【LeetCode-数组】生命游戏
题目描述
根据 百度百科 ,生命游戏,简称为生命,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态:1 即为活细胞(live),或 0 即为死细胞(dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
- 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
- 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
- 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
- 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
根据当前状态,写一个函数来计算面板上所有细胞的下一个(一次更新后的)状态。下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。
示例:
输入:
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
输出:
[
[0,0,0],
[1,0,1],
[0,1,1],
[0,1,0]
]
题目连接: https://leetcode-cn.com/problems/game-of-life/
思路1
通过当前细胞 board[i][j] 周围 8 个位置的细胞状态:
- 如果 board[i][j]==0 并且当前细胞周围有 3 个活细胞,则 board[i][j] = 1;
- 如果 board[i][j]==1 并且当前细胞周围的活细胞个数小于 2 个或者大于 3 个,则 board[i][j] = 0;
因为所有细胞是同时更新状态的,所以我们将原来的细胞状态复制一份,根据副本来判断当前细胞的下一个状态,这样的话判断当前细胞下一个状态时不受其他细胞下一个状态的影响。代码如下:
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int dirs[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}};
int rows = board.size();
int cols = board[0].size();
vector<vector<int>> copy = board;
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
int cnt = 0;
for(int k=0; k<8; k++){
int nr = i + dirs[k][0];
int nc = j + dirs[k][1];
if(nr>=0 && nr<rows && nc>=0 && nc<cols && board[nr][nc]==1) cnt++;
}
if(board[i][j]==0){
if(cnt==3) copy[i][j] = 1;
}else{
if(cnt<2 || cnt>3) copy[i][j] = 0;
}
}
}
board = copy;
}
};
- 时间复杂度:O(m × n)
- 空间复杂度:O(m × n)
思路2
思路一需要保存输入状态的一个副本,空间复杂度为 O(m x n),我们可以通过添加额外的状态来将空间复杂度降到 O(1)。
状态的变化有 3 种:0->1、1->0,不变。我们使用 3 表示 0 转为 1,例如,board[i][j]=3 说明 board[i][j] 之前的状态是 0,下一时刻的状态是 1,设为 3 是为了不影响其他细胞的状态。同理,board[i][j]=-1 说明 board[i][j] 之前的状态是 1,下一时刻的状态是 0. 当处理完成后,我们将数组中大于 0 的数都置为 1,其余的都置为 0. 代码如下:
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int dirs[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}};
int rows = board.size();
int cols = board[0].size();
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
int cnt = 0;
for(int k=0; k<8; k++){
int nr = i + dirs[k][0];
int nc = j + dirs[k][1];
if(nr>=0 && nr<rows && nc>=0 && nc<cols && abs(board[nr][nc])==1) cnt++;
}
if(board[i][j]==0){
if(cnt==3) board[i][j] = 2;
}else{
if(cnt<2 || cnt>3) board[i][j] = -1;
}
}
}
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
if(board[i][j]>0) board[i][j]=1;
else board[i][j] = 0;
}
}
}
};
- 时间复杂度:O(m × n)
- 空间复杂度:O(1)