算法初探LeetCode-生命游戏

134 阅读1分钟

LeetCode289. 生命游戏

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

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

  1. 如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡;
  2. 如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活;
  3. 如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡;
  4. 如果死细胞周围正好有三个活细胞,则该位置死细胞复活;

下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的,其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态,返回下一个状态。

示例 1:

输入: board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
输出: [[0,0,0],[1,0,1],[0,1,1],[0,1,0]]

示例 2:

输入: board = [[1,1],[1,0]]
输出: [[1,1],[1,1]]

提示:

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

思路分析

最难的核心个人认为是对于矩阵的边界问题处理,能不能找到一个统一的办法处理矩阵边界,因为不是什么时候,都有八宫格的。

对面板中的格子进行更新时,必须每次更新一个格子。但是题目要求所有格子需要同时被更新,因此需要根据面板的原始状态决定面板的新状态。

如果直接更新格子的值,在判断后面的格子是否需要更新时就无法知道前面的格子的原始值。为了避免前面格子的新值影响后面格子的更新,一个办法是将面板值复制出一份作为原始值,然后就能根据原始值得到面板上每个格子的新值。

具体而言,已知给定的面板 board 是 m 行 n 列的,创建一个 m 行 n 列的二维数组 original,将 board 的值复制到 original 中。然后遍历面板的每个位置,对于每个位置,计算 original 中的该位置的格子的相邻格子的活细胞数,并更新 board 中的该位置的值。

  • 如果 original 中的元素是 1,则当周围的活细胞数少于 2 个或多于 3 个时,board 中的对应元素变成 0,否则仍然是 1;

  • 如果 original 中的元素是 0,则当周围的活细胞数等于 3 个时,board 中的对应元素变成 1,否则仍然是 0。

算法代码

public void gameOfLife(int[][] board) {
    int[][] directions = {
        {
            -1, -1
        }, {
            -1, 0
        }, {
            -1, 1
        }, {
            0, 1
        }, {
            1, 1
        }, {
            1, 0
        }, {
            1, -1
        }, {
            0, -1
        }
    };
    int m = board.length, n = board[0].length;
    int[][] original = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            original[i][j] = board[i][j];
        }
    }
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            int count = 0;
            for (int[] direction: directions) {
                int newRow = i + direction[0], newColumn = j + direction[1];
                if (newRow >= 0 && newRow < m && newColumn >= 0 && newColumn < n) {
                    int value = original[newRow][newColumn];
                    if (value == 1) {
                        count++;
                    }
                }
            }
            if (original[i][j] == 1) {
                if (count < 2 || count > 3) {
                    board[i][j] = 0;
                }
            } else {
                if (count == 3) {
                    board[i][j] = 1;
                }
            }
        }
    }
}

结果详情

Snipaste_2023-06-30_15-26-56.png

算法复杂度

  • 空间复杂度:O(mn)O(m*n)
  • 时间复杂度:O(mn)O(m*n)

掘金(JUEJIN)一起进步,一起成长!