根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 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
解法一:辅助矩阵
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int neighbors[3] = {0, 1, -1};
int rows = board.size();
int cols = board[0].size();
vector<vector<int>> copyboard(rows, vector<int>(cols, 0));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
copyboard[i][j] = board[i][j];
}
}
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 = neighbors[j] + col;
if (r < rows && r >= 0 && c < cols && c >= 0 &&
copyboard[r][c] == 1)
liveneighbors++;
}
}
}
if (copyboard[row][col] == 1 &&
(liveneighbors < 2 || liveneighbors > 3))
board[row][col] = 0;
if (copyboard[row][col] == 0 && liveneighbors == 3)
board[row][col] = 1;
}
}
}
};
neighbors代表的是相对自己的位置变化,包括自身。rows和cols分别存放矩阵的行数和列数。现在创建一个和题目矩阵完全相同的矩阵,这是为了做到题目要求的同步更新,防止在要更新时需要同时更新多个细胞,如果直接在本来的矩阵上更新,那么要同步更新的一些操作会因为先更新的操作状态而影响到,所以这里复制一个副本,用来查看初始的矩阵。
然后循环遍历每一个细胞,liveneighbors代表的是邻居存活数量,初始化为0,用for循环嵌套遍历出去自身的邻居neighbors[i] == 0 && neighbors[j] == 0这里就是除去自身的操作,当他们不同时为零时,进入邻居存活计数,邻居的下标用相对于当前细胞的相对位置+当前细胞的位置表示,当当前邻居下标存在且邻居存活时,邻居存活数加一。遍历完当前细胞的邻居存活数之后,用规则判断当前细胞是否应该存活或者死亡。
解法二:原地变化
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
int neighbors[3] = {0, 1, -1};
int rows = board.size();
int cols = board[0].size();
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 = neighbors[j] + col;
if (r < rows && r >= 0 && c < cols && c >= 0 &&
(abs(board[r][c]) == 1))
liveneighbors++;
}
}
}
if (board[row][col] == 1 &&
(liveneighbors < 2 || liveneighbors > 3))
board[row][col] = -1;
if (board[row][col] == 0 && liveneighbors == 3)
board[row][col] = 2;
}
}
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (board[row][col] > 0)
board[row][col] = 1;
else
board[row][col] = 0;
}
}
}
};
首先,定义一个neighbors数组,其中存放了-1、0、1三个数,表示行方向和列方向的相对偏移量。
然后,获取二维数组的行数和列数。
接下来,通过两个嵌套的for循环遍历二维数组中的每个元素。
对于每个元素,我们需要计算它周围活细胞的数量。
我们使用两个嵌套的for循环,以当前元素为中心,在周围8个位置上移动。
如果移动后的位置在二维数组范围内并且该位置的绝对值是1,说明这是一个活细胞,则将liveneighbors加1。
接下来,根据康威生命游戏的规则来更新当前元素的状态。
如果当前元素是活细胞,并且它周围的活细胞数量小于2或大于3,说明它会死亡,将其状态设置为-1。
如果当前元素是死细胞,并且它周围的活细胞数量等于3,说明它会复活,将其状态设置为2。
完成所有元素的遍历后,我们需要再次遍历二维数组,将状态为大于0的细胞设置为活细胞,将其他情况的细胞设置为死细胞。
最后,原始二维数组就变成了经过一次康威生命游戏更新后的结果。