1. 程式人生 > >289. Game of Life

289. Game of Life

prev 一位 con and 技術 pan without 移動 之前

一、題目

  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     }

289. Game of Life