[LeetCode] 289. Game of Life

According to 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."

The board is made up of an m x n grid of cells, where each cell has an initial state: live (represented by a 1) or dead (represented by a 0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):

  1. Any live cell with fewer than two live neighbors dies as if caused by under-population.
  2. Any live cell with two or three live neighbors lives on to the next generation.
  3. Any live cell with more than three live neighbors dies, as if by over-population.
  4. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously. Given the current state of the m x n grid board, return the next state.

Example 1:

Input: board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
Output: [[0,0,0],[1,0,1],[0,1,1],[0,1,0]]

Example 2:

Input: board = [[1,1],[1,0]]
Output: [[1,1],[1,1]]

Constraints:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 25
  • board[i][j] is 0 or 1.

Follow up:

  • Could you solve it in-place? Remember that the board needs to be updated simultaneously: 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 upon the border of the array (i.e., live cells reach the border). How would you address these problems?

生命游戏。

根据 百度百科 , 生命游戏 ,简称为 生命 ,是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。

给定一个包含 m × n 个格子的面板,每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态: 1 即为 活细胞 (live),或 0 即为 死细胞 (dead)。每个细胞与其八个相邻位置(水平,垂直,对角线)的细胞都遵循以下四条生存定律:

如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
如果死细胞周围正好有三个活细胞,则该位置死细胞复活;
下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/game-of-life
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给一个 board,上面所有的元素表示细胞,细胞的死或活用 0 或 1 表示。并且有如下规则,对于每个细胞周围的八个细胞,

1. 如果小于两个活细胞,则当前细胞死亡;

2. 如果有两个或者三个活细胞,则当前细胞存活;

3. 如果大于三个活细胞,则当前细胞死亡;

4. 如果当前细胞死亡但是周围有三个活细胞,则当前细胞可以复活;

根据如上规则请更新这个 board 的存活情况。要求是 in-place 做。

这是一道模拟/实现的题目,注意不能使用额外空间。不用额外空间的题目还有73题。这个题因为要求不能创造额外空间,所以只能通过一个叫做状态机的东西来记录每个 cell 的状态改变。这里我再次引用grandyang大神的解释

状态0: 死细胞转为死细胞

状态1: 活细胞转为活细胞

状态2: 活细胞转为死细胞

状态3: 死细胞转为活细胞

按照这个状态的分布,可以把状态用二进制数标记。遍历 input,如果当前坐标是 1 的话(活细胞,二进制表达是 01),看下他周围活细胞的数量,记为 count,如果 count 是 2 或 3,则 +2,二进制变成 11。如果当前坐标是 0(死细胞,00)但是 count 是 3 的话,也 +2,二进制变成 10。按照这个思路就可以写代码了。

需要遍历 input 两次,第一次需要遍历 input 的每一个 cell,先算出每个 cell 周围的八个 cell 有几个是活的,以得出当前 cell 的存活情况。第二次遍历的时候对每个位置上的数字除以 2,如果是状态 1 和 3,第二次遍历的时候依然是 1,依然会存活;但是 0 和 2 在第二次遍历的时候就会变为 0 而死亡。

时间O(mn)

空间O(1)

Java实现,38行需要 continue 是因为那是当前坐标。

 1 class Solution {
 2     public void gameOfLife(int[][] board) {
 3         // corner case
 4         if (board == null || board.length == 0) {
 5             return;
 6         }
 7 
 8         // normal case
 9         int m = board.length;
10         int n = board[0].length;
11         for (int i = 0; i < m; i++) {
12             for (int j = 0; j < n; j++) {
13                 int count = helper(board, i, j);
14                 // 当前是活的,下一轮还活着,因为3的二进制11右移一位变成1
15                 if (board[i][j] == 1) {
16                     if (count == 2 || count == 3) {
17                         board[i][j] += 2;
18                     }
19                 }
20                 // 当前是死的,下一轮复活,因为2的二进制10右移一位变成1
21                 else if (count == 3) {
22                     board[i][j] += 2;
23                 }
24             }
25         }
26         for (int i = 0; i < m; i++) {
27             for (int j = 0; j < n; j++) {
28                 // board[i][j] = board[i][j] / 2;
29                 board[i][j] = board[i][j] >> 1;
30             }
31         }
32     }
33 
34     private int helper(int[][] board, int i, int j) {
35         int count = 0;
36         for (int row = Math.max(0, i - 1); row <= Math.min(i + 1, board.length - 1); row++) {
37             for (int col = Math.max(0, j - 1); col <= Math.min(j + 1, board[0].length - 1); col++) {
38                 if (row == i && col == j) {
39                     continue;
40                 }
41                 // 这里1,3和1做AND操作的结果都会是1
42                 if ((board[row][col] & 1) == 1) {
43                     count++;
44                 }
45             }
46         }
47         return count;
48     }
49 }

 

JavaScript实现

 1 /**
 2  * @param {number[][]} board
 3  * @return {void} Do not return anything, modify board in-place instead.
 4  */
 5 var gameOfLife = function(board) {
 6     // corner case
 7     if (board == null || board.length == 0) {
 8         return;
 9     }
10 
11     // normal case
12     let m = board.length;
13     let n = board[0].length;
14     for (let i = 0; i < m; i++) {
15         for (let j = 0; j < n; j++) {
16             let count = helper(board, i, j);
17             if (board[i][j] == 1) {
18                 if (count == 2 || count == 3) {
19                     board[i][j] += 2;
20                 }
21             } else if (count == 3) {
22                 board[i][j] += 2;
23             }
24         }
25     }
26     for (let i = 0; i < m; i++) {
27         for (let j = 0; j < n; j++) {
28             board[i][j] = board[i][j] >> 1;
29         }
30     }
31 };
32 
33 var helper = function(board, i, j) {
34     let count = 0;
35     for (
36         let row = Math.max(0, i - 1);
37         row <= Math.min(i + 1, board.length - 1);
38         row++
39     ) {
40         for (
41             let col = Math.max(0, j - 1);
42             col <= Math.min(j + 1, board[0].length - 1);
43             col++
44         ) {
45             if (row == i && col == j) {
46                 continue;
47             }
48             if ((board[row][col] & 1) == 1) {
49                 count++;
50             }
51         }
52     }
53     return count;
54 };

 

相关题目

73. Set Matrix Zeroes

289. Game of Life

LeetCode 题目总结

posted @ 2020-02-15 07:36  CNoodle  阅读(242)  评论(0编辑  收藏  举报