生命游戏
根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。
给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:
如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡; 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活; 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡; 如果死细胞周围正好有三个活细胞,则该位置死细胞复活; 下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是 同时 发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。
给定当前 board 的状态,更新 board 到下一个状态。
注意 你不需要返回任何东西。
示例 1:

codeType
输入: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:

codeType
输入: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(mn)
进阶做法:可以通过定义新的状态来表示细胞之前和现在的状态,这样可以把空间复杂度降到O(1)
ts
/**
Do not return anything, modify board in-place instead.
*/
function gameOfLife(board: number[][]): void {
// 因为出生和死亡是同时发生的,所以不能边遍历边进行更新。
// 简单的做法就是一遍遍历,把每个位置的新状态记录下来,最后更新回原矩阵,这样需要的空间就是O(mn)
// 可以额外定义一个状态,之前只有0死、1活
// 可以定义新状态2之前是死的,现在是活的;状态3之前是活的,现在是死的
const n = board.length
const m = board[0].length
for(let i = 0; i < n; i++){
for(let j = 0; j < m; j++){
let count = 0
// 遍历当前格子的周围8个细胞
for(let row = -1; row < 2; row++){
for(let col = -1; col < 2; col++){
if(row === 0 && col === 0){ // 排除本身
continue
}else if((i + row >= 0) && (i + row < n) && (j + col >= 0) && (j + col < m)){ // 有效范围
if(board[i + row][j + col] === 1 || board[i + row][j + col] === 3){
// 细胞存活数量+1
count++
}
}
}
}
// 计算结果
let res = 0
if((count < 2 || count > 3)&&(board[i][j] === 1)){ // 活细胞死亡
res = 3
}else if((count === 2 || count === 3)&&(board[i][j] === 1)){ // 活细胞存活
res = 1
}else if(count === 3 && board[i][j] === 0){ // 死细胞复活
res = 2
}else{
// 死细胞死亡
res = 0
}
board[i][j] = res
}
}
for(let i = 0; i < n; i++){
for(let j = 0; j < m; j++){
if(board[i][j] === 2){
board[i][j] = 1
}else if(board[i][j] === 3){
board[i][j] = 0
}
}
}
};