【面试经典150 | 矩阵】生命游戏

文章目录

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更......
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【矩阵】【数组】


题目来源

面试经典150 | 289. 生命游戏


题目解读

根据一些四条生存规则来完成对网格面板的更新,并且更新是同时发生的。


解题思路

方法一: O ( m n ) O(mn) O(mn) 额外空间

八个方向

首先明确网格点的八个更新方向:左边、左上、正上、右上、右边、右下、正下、左下。我们可以嵌套枚举 dirs = [0, -1, 0] 来实现以上的八个方向。

四条生存准则

每个网格点代表一个细胞,每个细胞有一个状态,1 表示活细胞,0 表示死细胞,细胞的更新规则如下:

  • (1)活细胞周围八个方向位置上活细胞数小于两个,该位置细胞死亡;
  • (2)活细胞周围八个方向位置上的活细胞数等于两个或三个,该位置细胞仍然存活;
  • (3)活细胞周围八个方向位置上活细胞数超过三个,该位置细胞死亡;
  • (4)死细胞周围八个方向位置上活细胞数等于三个,该位置细胞复活;

枚举每一个网格上的细胞,如果是活细胞,那么按照规则(1)(2)(3)更新 board;如果是死细胞,按照规则(4)更新 board

但是,需要复制 board 得到 copyBoard,利用 copyBoard 来判断当前细胞的状态(死亡还是存活),更新最后的结果到 board 上。

实现代码

cpp 复制代码
class Solution {
public:
    void gameOfLife(vector<vector<int>>& board) {
        int dirs[] = {0, -1, 1};
        int rows = board.size();
        int cols = board[0].size();

        vector<vector<int>> copyBoard = board;
        for (int row = 0; row < rows; ++row) {
            for (int col = 0; col < cols; ++col) {
                int cnts = 0;   // 表示周围相邻的八个方向上活细胞的数量
                for (int i = 0; i < 3; ++i) {
                    for (int j = 0; j < 3; ++j) {
                        if (!(dirs[i] == 0 && dirs[j] == 0)) {
                            int nRow = row + dirs[i];
                            int nCol = col + dirs[j];

                            // 更新 cnts
                            if (nRow >= 0 && nRow < rows && nCol >= 0 && nCol < cols && copyBoard[nRow][nCol] == 1) cnts += 1;
                        }
                    }
                }
                // 规则(1)(3)
                if (copyBoard[row][col] == 1 && (cnts < 2 || cnts > 3)) 
                    board[row][col] = 0;
                // 规则(4)
                if (copyBoard[row][col] == 0 && cnts == 3)
                    board[row][col] = 1;
            }
        }
    }
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn), m m m 为数组 board 的行数, n n n 为数组 board 的列数。

空间复杂度: O ( m n ) O(mn) O(mn),额外空间是辅助数组 copyBoard 使用的空间。

方法二: O ( 1 ) O(1) O(1) 额外空间

在本题中,如果细胞的状态发生了变化,一共只有两种:

  • 细胞从存活的状态转变成死亡的状态;
  • 细胞从死亡的状态转变成存活的状态。

于是,我们可以在按照规则进行判断时,如果 "细胞从存活的状态转变成死亡的状态",我们将 board 中该位置的转态置为 -1;如果 "细胞从死亡的状态转变成存活的状态",我们将 board 中该位置的状态置为 2。这里的 -12 可以是任意的数字,只要不和 01 重复即可。

需要注意的是,判断当前网格细胞是否是存活状态还要考虑 board[row][col] = -1 的情况。

最后,遍历 board,根据表示 "细胞从存活的状态转变成死亡的状态" 的 -1,将 board 中该位置置为 0,根据表示 "细胞从死亡的状态转变成存活的状态" 的 2,将 board 中该位置置为 1

实现代码

cpp 复制代码
class Solution {
public:
    void gameOfLife(vector<vector<int>>& board) {
        int dirs[] = {0, -1, 1};
        int rows = board.size();
        int cols = board[0].size();

        for (int row = 0; row < rows; ++row) {
            for (int col = 0; col < cols; ++col) {
                int cnts = 0;   // 表示周围相邻的八个方向上活细胞的数量
                for (int i = 0; i < 3; ++i) {
                    for (int j = 0; j < 3; ++j) {
                        if (!(dirs[i] == 0 && dirs[j] == 0)) {
                            int nRow = row + dirs[i];
                            int nCol = col + dirs[j];

                            // 更新 cnts
                            if (nRow >= 0 && nRow < rows && nCol >= 0 && nCol < cols && (abs(board[nRow][nCol]) == 1)) cnts += 1;
                        }
                    }
                }
                // 规则(1)(3)
                if (board[row][col] == 1 && (cnts < 2 || cnts > 3)) 
                    board[row][col] = -1;
                // 规则(4)
                if (board[row][col] == 0 && cnts == 3)
                    board[row][col] = 2;
            }
        }
        for (int row = 0; row < rows; ++row) {
            for (int col = 0; col < cols; ++col) {
                if (board[row][col] == -1) board[row][col] = 0;
                if (board[row][col] == 2) board[row][col] = 1;
            }
        }
    }
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn), m m m 为数组 board 的行数, n n n 为数组 board 的列数。

空间复杂度: O ( 1 ) O(1) O(1)。


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

相关推荐
不去幼儿园36 分钟前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
Mr_Xuhhh38 分钟前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
Ajiang28247353042 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
盼海2 小时前
排序算法(五)--归并排序
数据结构·算法·排序算法
网易独家音乐人Mike Zhou5 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’6 小时前
C++ list (链表)容器
c++·链表·list
Guofu_Liao6 小时前
大语言模型---LoRA简介;LoRA的优势;LoRA训练步骤;总结
人工智能·语言模型·自然语言处理·矩阵·llama
机器视觉知识推荐、就业指导8 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Swift社区9 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展