289. Game of Life

一、题目

  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     }

 

posted @ 2018-11-24 22:26  skillking2  阅读(79)  评论(0编辑  收藏