0289. Game of Life (M)
Game of Life (M)
题目
According to the Wikipedia's article: "The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970."
Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):
- Any live cell with fewer than two live neighbors dies, as if caused by under-population.
- Any live cell with two or three live neighbors lives on to the next generation.
- Any live cell with more than three live neighbors dies, as if by over-population..
- Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
Write a function to compute the next state (after one update) of the board given its current state. The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously.
Example:
Input:
[
[0,1,0],
[0,0,1],
[1,1,1],
[0,0,0]
]
Output:
[
[0,0,0],
[1,0,1],
[0,1,1],
[0,1,0]
]
Follow up:
- Could you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells.
- In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?
题意
细胞游戏:一个细胞有生死两种状态,如果一个细胞周围活着的细胞个数小于2或大于3,则该细胞死亡;若个数为2,则状态不变;若个数为3,则该细胞生还。给定某一个时刻的细胞状态数组,要求返回下一时刻的细胞状态数组。
思路
题目要求状态的变化是同时进行的,因此不能先计算出一个细胞的状态,再用这个更新后的状态去计算其他细胞的状态,且要求仅在原数组上进行修改。
最简单的方法是直接将原数组复制一份,每次查询邻接生存细胞个数都以这个拷贝数组为基准。
原地修改方法:扩展数组中的值类型如下:
0 -- dead -> dead
1 -- live -> live
2 -- dead -> live
3 -- live -> dead
第一次遍历,将数组中的值按要求修改为扩展值,第二次遍历再将修改完的扩展值改回0和1。
代码实现
Java
拷贝
class Solution {
public void gameOfLife(int[][] board) {
int m = board.length, n = board[0].length;
int[][] copy = new int[m][];
for (int i = 0; i < m; i++) {
copy[i] = Arrays.copyOf(board[i], n);
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int count = count(copy, i, j, m, n);
if (count < 2 || count > 3) {
board[i][j] = 0;
} else if (count == 3) {
board[i][j] = 1;
}
}
}
}
private int count(int[][] board, int i, int j, int m, int n) {
int[] diff = { -1, 0, 1 };
int count = 0;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
int nextI = i + diff[x], nextJ = j + diff[y];
if (!(x == 1 && y == 1) && isValid(nextI, nextJ, m, n) && board[nextI][nextJ] == 1) {
count++;
}
}
}
return count;
}
private boolean isValid(int i, int j, int m, int n) {
return i >= 0 && i < m && j >= 0 && j < n;
}
}
原地
class Solution {
public void gameOfLife(int[][] board) {
int m = board.length, n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int count = count(board, i, j, m, n);
int origin = board[i][j];
if (count < 2 || count > 3) {
board[i][j] = origin == 0 ? 0 : 3;
} else if (count == 3) {
board[i][j] = origin == 0 ? 2 : 1;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
int value = board[i][j];
board[i][j] = value == 3 ? 0 : value == 2 ? 1 : value;
}
}
}
private int count(int[][] board, int i, int j, int m, int n) {
int[] diff = { -1, 0, 1 };
int count = 0;
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
int nextI = i + diff[x], nextJ = j + diff[y];
if (!(x == 1 && y == 1) && isValid(nextI, nextJ, m, n) && board[nextI][nextJ] % 2 == 1) {
count++;
}
}
}
return count;
}
private boolean isValid(int i, int j, int m, int n) {
return i >= 0 && i < m && j >= 0 && j < n;
}
public static void main(String[] args) {
Solution s = new Solution();
s.gameOfLife(new int[][] { { 0, 1, 0 }, { 0, 0, 1 }, { 1, 1, 1 }, { 0, 0, 0 } });
}
}
JavaScript
/**
* @param {number[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var gameOfLife = function (board) {
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
let count = countNeighbor(board, i, j)
let origin = board[i][j]
if (origin === 1 || origin === 2) {
board[i][j] = count === 2 || count === 3 ? 1 : 3
} else {
board[i][j] = count === 3 ? 2 : 0
}
}
}
for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[0].length; j++) {
let origin = board[i][j]
board[i][j] = origin === 1 || origin === 2 ? 1 : 0
}
}
}
let countNeighbor = function (board, i, j) {
let count = 0
for (let diffI = -1; diffI <= 1; diffI++) {
for (let diffJ = -1; diffJ <= 1; diffJ++) {
let nextI = i + diffI
let nextJ = j + diffJ
if (isValid(board, nextI, nextJ) && (nextI !== i || nextJ !== j) && board[nextI][nextJ] % 2) {
count++
}
}
}
return count
}
let isValid = function (board, i, j) {
let m = board.length
let n = board[0].length
return i >= 0 && i < m && j >= 0 && j < n
}