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):
Write a function to compute the next state (after one update) of the board given its current state.
Follow up:
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
康威生命游戏(英语:Conway's Game of Life),又称康威生命棋,是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
生命游戏中,对于任意细胞,规则如下:
每个细胞有两种状态-存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。
可以把最初的细胞结构定义为种子,当所有在种子中的细胞同时被以上规则处理后, 可以得到第一代细胞图。按规则继续处理当前的细胞图,可以得到下一代的细胞图,周而复始。
解法1:最简单的方法是新建一个矩阵保存新结果,但题目要求in-place解时,如果直接根据每个点周围的存活数量来修改当前值,由于矩阵是顺序遍历的,这样会影响到下一个点的计算。如何在修改值的同时又保证下一个点的计算不会被影响呢?实际上我们只要将值稍作编码就行了,因为题目给出的是一个int矩阵,大有空间可以利用。这里我们假设对于某个点,值的含义为
0 : 上一轮是0,这一轮过后还是0
1 : 上一轮是1,这一轮过后还是1
2 : 上一轮是1,这一轮过后变为0
3 : 上一轮是0,这一轮过后变为1
这样,对于一个节点来说,如果它周边的点是1或者2,就说明那个点上一轮是活的。最后,在遍历一遍数组,把我们编码再解回去,即0和2都变回0,1和3都变回1,就行了。
解法2: 位运算(bit manipulation),由于细胞只有两种状态0和1,因此可以使用二进制来表示细胞的生存状态,更新细胞状态时,将细胞的下一个状态用高位进行存储,全部更新完毕后,将细胞的状态右移一位。
参考:ethannnli
Java:
public 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 lives = 0; // 判断上边 if(i > 0){ lives += board[i - 1][j] == 1 || board[i - 1][j] == 2 ? 1 : 0; } // 判断左边 if(j > 0){ lives += board[i][j - 1] == 1 || board[i][j - 1] == 2 ? 1 : 0; } // 判断下边 if(i < m - 1){ lives += board[i + 1][j] == 1 || board[i + 1][j] == 2 ? 1 : 0; } // 判断右边 if(j < n - 1){ lives += board[i][j + 1] == 1 || board[i][j + 1] == 2 ? 1 : 0; } // 判断左上角 if(i > 0 && j > 0){ lives += board[i - 1][j - 1] == 1 || board[i - 1][j - 1] == 2 ? 1 : 0; } //判断右下角 if(i < m - 1 && j < n - 1){ lives += board[i + 1][j + 1] == 1 || board[i + 1][j + 1] == 2 ? 1 : 0; } // 判断右上角 if(i > 0 && j < n - 1){ lives += board[i - 1][j + 1] == 1 || board[i - 1][j + 1] == 2 ? 1 : 0; } // 判断左下角 if(i < m - 1 && j > 0){ lives += board[i + 1][j - 1] == 1 || board[i + 1][j - 1] == 2 ? 1 : 0; } // 根据周边存活数量更新当前点,结果是0和1的情况不用更新 if(board[i][j] == 0 && lives == 3){ board[i][j] = 3; } else if(board[i][j] == 1){ if(lives < 2 || lives > 3) board[i][j] = 2; } } } // 解码 for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] = board[i][j] % 2; } } } }
Java: Bit Manipulate, 位操作,将下轮该cell要变的值存入bit2中,然后还原的时候右移就行了。
public void solveInplaceBit(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 lives = 0; // 累加上下左右及四个角还有自身的值 for(int y = Math.max(i - 1, 0); y <= Math.min(i + 1, m - 1); y++){ for(int x = Math.max(j - 1, 0); x <= Math.min(j + 1, n - 1); x++){ // 累加bit1的值 lives += board[y][x] & 1; } } // 如果自己是活的,周边有两个活的,lives是3 // 如果自己是死的,周边有三个活的,lives是3 // 如果自己是活的,周边有三个活的,lives减自己是3 if(lives == 3 || lives - board[i][j] == 3){ board[i][j] |= 2; } } } // 右移就是新的值 for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] >>>= 1; } } }
Python: Bit Manipulate
class Solution(object): def gameOfLife(self, board): """ :type board: List[List[int]] :rtype: void Do not return anything, modify board in-place instead. """ dx = (1, 1, 1, 0, 0, -1, -1, -1) dy = (1, 0, -1, 1, -1, 1, 0, -1) for x in range(len(board)): for y in range(len(board[0])): lives = 0 for z in range(8): nx, ny = x + dx[z], y + dy[z] lives += self.getCellStatus(board, nx, ny) if lives + board[x][y] == 3 or lives == 3: board[x][y] |= 2 for x in range(len(board)): for y in range(len(board[0])): board[x][y] >>= 1
def getCellStatus(self, board, x, y): if x < 0 or y < 0 or x >= len(board) or y >= len(board[0]): return 0 return board[x][y] & 1
Python:
class Solution(object): def gameOfLife(self, board): """ :type board: List[List[int]] :rtype: void Do not return anything, modify board in-place instead. """ m = len(board) n = len(board[0]) if m else 0 for i in xrange(m): for j in xrange(n): count = 0 ## Count live cells in 3x3 block. for I in xrange(max(i-1, 0), min(i+2, m)): for J in xrange(max(j-1, 0), min(j+2, n)): count += board[I][J] & 1 # if (count == 4 && board[i][j]) means: # Any live cell with three live neighbors lives. # if (count == 3) means: # Any live cell with two live neighbors. # Any dead cell with exactly three live neighbors lives. if (count == 4 and board[i][j]) or count == 3: board[i][j] |= 2 # Mark as live. for i in xrange(m): for j in xrange(n): board[i][j] >>= 1 # Update to the next state.
C++:
class Solution { public: void gameOfLife(vector<vector<int> >& board) { int m = board.size(), n = m ? board[0].size() : 0; int dx[] = {-1, -1, -1, 0, 1, 1, 1, 0}; int dy[] = {-1, 0, 1, 1, 1, 0, -1, -1}; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { int cnt = 0; for (int k = 0; k < 8; ++k) { int x = i + dx[k], y = j + dy[k]; if (x >= 0 && x < m && y >= 0 && y < n && (board[x][y] == 1 || board[x][y] == 2)) { ++cnt; } } if (board[i][j] && (cnt < 2 || cnt > 3)) board[i][j] = 2; else if (!board[i][j] && cnt == 3) board[i][j] = 3; } } for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { board[i][j] %= 2; } } } };
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。