Game of Life 生命游戏(Medium)
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."
- 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.
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?
3.
题目大意:
根据维基百科的文章:“生命游戏,也被简称为生命,是一款由英国数学家约翰·霍顿康威于1970年设计的细胞自动机。”
给定一个m * n的细胞隔板,每一个细胞拥有一个初始状态:存活(1)或者死亡(0)。每一个细胞与其周围的8个邻居细胞(水平,竖直,对角线)发生交互,依据如下四条规则(摘自维基百科):
任何相邻存活细胞数小于2个的存活细胞都会死亡,模拟人口不足。
任何相邻存活细胞数为2个或者3个的存活细胞会存活到下一代。
任何相邻存活细胞数大于3个的存活细胞都会死亡,模拟人口过载。
任何相邻存活细胞数等于3个的死亡细胞都会成为一个存活细胞,模拟繁殖。
编写函数,根据隔板的当前状态,计算其下一个状态(一次更新之后)
进一步思考:
你可以就地完成题目吗?记住隔板需要同时更新:你不能先更新某些细胞然后再以其变更后的值来更新其他细胞。
在这个问题中,我们使用2维数组表示隔板。原则上,隔板是无穷的,这可能导致一些边界问题。你怎么处理边界问题?
解题思路
To solve it in place, we use 2 bits to store 2 states:
[2nd bit, 1st bit] = [next state, current state]
- 00 dead (next) <- dead (current)
- 01 dead (next) <- live (current)
- 10 live (next) <- dead (current)
- 11 live (next) <- live (current)
- In the beginning, every cell is either 00 or 01.
- Notice that 1st state is independent of 2nd state.
- Imagine all cells are instantly changing from the 1st to the 2nd state, at the same time.
- Let's count # of neighbors from 1st state and set 2nd state bit.
- Since every 2nd state is by default dead, no need to consider transition 01 -> 00.
- In the end, delete every cell's 1st state by doing >> 1.
For each cell's 1st bit, check the 8 pixels around itself, and set the cell's 2nd bit.
Transition 01 -> 11: when board == 1 and lives >= 2 && lives <= 3.
Transition 00 -> 10: when board == 0 and lives == 3.
To get the current state, simply do
board[i][j] & 1
To get the next state, simply do
board[i][j] >> 1
Hope this helps!
public void gameOfLife(int[][] board) {
if(board == null || board.length == 0) return;
int m = board.length, n = board[0].length;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
int lives = liveNeighbors(board, m, n, i, j);
// In the beginning, every 2nd bit is 0;
// So we only need to care about when the 2nd bit will become 1.
if(board[i][j] == 1 && lives >= 2 && lives <= 3) {
board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11
}
if(board[i][j] == 0 && lives == 3) {
board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10
}
}
}
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
board[i][j] >>= 1; // Get the 2nd state.
}
}
}
public int liveNeighbors(int[][] board, int m, int n, int i, int j) {
int lives = 0;
for(int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) {
for(int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) {
lives += board[x][y] & 1;
}
}
lives -= board[i][j] & 1;
return lives;
}
Reference
1 neverlandly: Game of Life