力扣经典150题第三十八题:生命游戏

简介: 力扣经典150题第三十八题:生命游戏

力扣经典150题第三十八题:生命游戏

引言

本篇博客介绍了力扣经典150题中的第三十八题:生命游戏。生命游戏是约翰·康威在1970年发明的细胞自动机,每个细胞的状态由其周围的八个相邻细胞状态决定。根据题目要求,我们需要实现一个原地算法,将给定的 m x n 网格面板 board 的当前状态转换为下一个状态。

题目详解

给定一个 m x n 网格面板 board,每个格子的状态是 1(活细胞)或 0(死细胞)。根据生存定律,下一个状态的细胞状态取决于周围八个相邻位置的细胞状态。

具体生存定律如下:

  • 如果活细胞周围的活细胞数少于两个,则该位置活细胞死亡。
  • 如果活细胞周围有两个或三个活细胞,则该位置活细胞仍然存活。
  • 如果活细胞周围有超过三个活细胞,则该位置活细胞死亡。
  • 如果死细胞周围恰好有三个活细胞,则该位置死细胞复活。

要求使用原地算法实现状态转换,即在不使用额外空间的情况下,直接修改给定的 board。

解题思路

为了实现原地算法,我们可以使用额外的状态表示当前细胞状态和下一个状态。

具体步骤如下:

  1. 使用额外状态表示细胞的当前状态和下一个状态。这里可以用两位二进制数来表示,比如 00 表示死细胞到死细胞,01 表示活细胞到死细胞,10 表示死细胞到活细胞,11 表示活细胞到活细胞。
  2. 遍历原始矩阵,计算每个细胞周围的活细胞数量,并根据当前状态确定下一个状态。
  3. 根据下一个状态更新原始矩阵。

通过上述步骤,可以实现原地算法来更新生命游戏的状态。

代码实现

public class GameOfLife {
    public void gameOfLife(int[][] board) {
        int m = board.length;
        int n = board[0].length;
        // 遍历矩阵,根据当前状态确定下一个状态
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int liveNeighbors = countLiveNeighbors(board, i, j, m, n);
                // 根据当前状态和周围活细胞数量确定下一个状态
                if (board[i][j] == 1) {
                    if (liveNeighbors < 2 || liveNeighbors > 3) {
                        // 活细胞死亡
                        board[i][j] = 3; // 01
                    }
                } else {
                    if (liveNeighbors == 3) {
                        // 死细胞复活
                        board[i][j] = 2; // 10
                    }
                }
            }
        }
        // 更新矩阵为下一个状态
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j] >>= 1; // 右移一位得到下一个状态
            }
        }
    }
    // 计算某个细胞周围的活细胞数量
    private int countLiveNeighbors(int[][] board, int x, int y, int m, int n) {
        int[][] directions = {
            {-1, -1}, {-1, 0}, {-1, 1},
            {0, -1},         {0, 1},
            {1, -1}, {1, 0}, {1, 1}
        };
        int liveCount = 0;
        for (int[] dir : directions) {
            int nx = x + dir[0];
            int ny = y + dir[1];
            if (nx >= 0 && nx < m && ny >= 0 && ny < n) {
                if (board[nx][ny] == 1 || board[nx][ny] == 3) {
                    liveCount++;
                }
            }
        }
        return liveCount;
    }
    public static void main(String[] args) {
        GameOfLife solution = new GameOfLife();
        // 示例测试
        int[][] board1 = {{0, 1, 0}, {0, 0, 1}, {1, 1, 1}, {0, 0, 0}};
        System.out.println("输入矩阵1:");
        printMatrix(board1);
        solution.gameOfLife(board1);
        System.out.println("下一个状态矩阵1:");
        printMatrix(board1);
        int[][] board2 = {{1, 1}, {1, 0}};
        System.out.println("输入矩阵2:");
        printMatrix(board2);
        solution.gameOfLife(board2);
        System.out.println("下一个状态矩阵2:");
        printMatrix(board2);
    }
    private static void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            System.out.println(Arrays.toString(row));
        }
        System.out.println();
    }
}

示例演示

展示了两个不同的矩阵输入,并输出了生命游戏的下一个状态矩阵。

复杂度分析

该解法的时间复杂度为 O(m * n),空间复杂度为 O(1),满足题目要求的原地修改条件。

总结

本篇博客介绍了如何使用原地

算法实现生命游戏的状态转换。通过额外状态表示当前状态和下一个状态,并根据生存定律更新矩阵,最终实现了生命游戏的状态转换。

相关文章
|
6月前
LeetCode题:174. 地下城游戏
LeetCode题:174. 地下城游戏
63 0
LeetCode题:174. 地下城游戏
|
1月前
|
算法
Leetcode第45题(跳跃游戏II)
这篇博客文章讨论了如何使用贪心算法解决LeetCode第45题“跳跃游戏II”,目的是找到使用最少跳跃次数到达数组末尾的策略。
73 8
Leetcode第45题(跳跃游戏II)
|
3月前
|
算法
LeetCode第55题跳跃游戏
LeetCode第55题"跳跃游戏"的解题方法,通过记录当前最远可达到的位置并判断每个位置是否可达以及能否到达末尾,有效解决了跳跃至数组末尾的可行性问题。
LeetCode第55题跳跃游戏
|
1月前
Leetcode第55题(跳跃游戏)
LeetCode第55题“跳跃游戏”要求判断在一个非负整数数组中,从第一个位置出发,是否能够到达最后一个位置,其中每个位置的元素代表可跳跃的最大长度。
27 0
|
3月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
50 1
|
3月前
|
Python
【Leetcode刷题Python】174. 地下城游戏
LeetCode 174题 "地下城游戏" 的Python解决方案,使用动态规划算法计算骑士从左上角到右下角拯救公主所需的最低初始健康点数。
51 3
|
3月前
|
算法 索引 Python
【Leetcode刷题Python】55. 跳跃游戏
解决LeetCode "跳跃游戏"问题的Python实现代码,使用了贪心算法的思路。代码中初始化最远可到达位置 max_k,并遍历数组 nums,通过更新 max_k 来记录每次能跳到的最远位置,如果在任何时刻 max_k 大于或等于数组的最后一个索引,则返回 True,表示可以到达数组的末尾;如果当前索引 i 超出了 max_k,则返回 False,表示无法继续前进。时间复杂度为 O(n),空间复杂度为 O(1)。
49 1
|
3月前
|
算法
LeetCode第45题跳跃游戏 II
LeetCode第45题"跳跃游戏 II"的解题方法,通过一次循环和选择每个位置的最大可跳距离,有效减少了跳跃次数,简化了问题。
|
5月前
力扣-2029-石子游戏-‘屎山’代码
力扣-2029-石子游戏-‘屎山’代码
40 3
|
5月前
|
算法 数据挖掘 开发者
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】
LeetCode题目55:跳跃游戏【python5种算法贪心/回溯/动态规划/优化贪心/索引哈希映射 详解】