一、题目
1、审题
2、分析
编程实现 “LIFE” 这个游戏:
①、若 m 的周围8个邻居细胞中存活的细胞数 < 2,则此细胞从存活状态变为死亡状态;
②、若 m 的周围8个邻居细胞中存活的细胞数 = 2 或 = 3,则此细胞从存活状态变为存活状态;
③、若 m 的周围8个邻居细胞中存活的细胞数 > 3,则此细胞从存活状态变为死亡状态;
③、若 m 的周围8个邻居细胞中存活的细胞数 = 3,则此细胞从死亡状态变为存活状态;
只能一次性更新所有的细胞的状态,不能用改变后的状态来判断后边的细胞的状态。
其中 1代表存活状态,0 代表死亡状态。
二、解答
1、思路
方法一、
①、采用两个 bit 位来表示状态。刚开始,所有细胞全部是 00 或者 01;
②、注意状态 1 与状态 2 是独立的。
③、所有的细胞是同时从状态 1 变为状态 2的。
④、计算所有细胞在未变化之前的所有邻居细胞的状态,并记录此细胞将要变化的状态2。
⑤、因为状态 2 默认为 0,即死亡状态,故不需要考虑状态转变: 01 --> 00
⑥、最终,通过 >> 1 向右移动一位,删除所有细胞的状态 1.
⑦、每一个细胞的状态 2 的计算方法:
01 --> 11: 当 board == 1 并且 2 <= lives && lives <= 3;
00 --> 10: 当 board == 0 并且 lives == 3。
⑧、获取当前的细胞的状态: board[i][j] & 1
⑨、获取细胞将要变化的状态: board[i][j] >> 1
1 public void gameOfLife(int[][] board) { 2 if(board == null || board.length == 0) 3 return; 4 int m = board.length, n = board[0].length; 5 6 // In the beginning, every 2nd bit is 0; 7 // So we only need to care about when will the 2nd bit become 1. 8 for(int i = 0; i < m; i++) { 9 for (int j = 0; j < n; j++) { 10 int lives = liveNeighbors(board, m, n, i, j); 11 if(board[i][j] == 1 && 2 <= lives && lives <= 3) 12 board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11 13 if(board[i][j] == 0 && lives == 3) 14 board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10 15 } 16 } 17 18 for(int i = 0; i < m; i++) 19 for (int j = 0; j < n; j++) 20 board[i][j] >>= 1; 21 } 22 23 private int liveNeighbors(int[][] board, int m, int n, int i, int j) { 24 int lives = 0; 25 for(int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) { 26 for (int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) { 27 lives += board[x][y] & 1; 28 } 29 } 30 lives -= board[i][j] & 1; 31 return lives; 32 }
方法二、
可以通过值不是 0 和 1 的两个常量记录此细胞将要变化的状态。
从而不影响统计出其他细胞的周围的存活细胞数。
最终在循环给元素赋更新的值。
1 int live = 3; 2 int die = 2; 3 public void gameOfLife2(int[][] board) { 4 if(board == null || board.length == 0) 5 return; 6 int rows = board.length, cols = board[0].length; 7 // we only flip the 1 to die and 0 to live 8 // so when we find a die around, it must be a previous 1 9 // then we can count the 1s without being affected 10 for (int i = 0; i < rows; i++) { 11 for (int j = 0; j < cols; j++) { 12 int around = countLive(i, j, board); 13 if(board[i][j] == 0 && around == 3) 14 board[i][j] = live; 15 else if(board[i][j] == 1) { 16 if(around == 2 || around == 3) 17 continue; 18 if(around < 2 || around > 3) 19 board[i][j] = die; 20 } 21 } 22 } 23 for (int i=0;i<rows;i++){ 24 for (int j=0;j<cols;j++){ 25 if (board[i][j] == die) 26 board[i][j] = 0; 27 if (board[i][j] == live) 28 board[i][j] = 1; 29 } 30 } 31 } 32 33 private int countLive(int i, int j, int[][] board) { 34 int count = 0; 35 int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}}; 36 37 for (int[] dir:dirs){ 38 int x = i+dir[0]; 39 int y = j+dir[1]; 40 41 if (x>=0 && y>=0 && x < board.length && y<board[0].length ){ 42 43 if (board[x][y] == 1 || board[x][y] == die) 44 count ++; 45 } 46 } 47 48 return count; 49 }