春招冲刺百题计划--矩阵篇

news2024/11/28 5:34:58



289. 生命游戏

题目:

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

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

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

思考:

方法一:暴力破解

这个问题看起来很简单,但有一个陷阱,如果你直接根据规则更新原始数组,那么就做不到题目中说的 同步 更新。假设你直接将更新后的细胞状态填入原始数组,那么当前轮次其他细胞状态的更新就会引用到当前轮已更新细胞的状态,但实际上每一轮更新需要依赖上一轮细胞的状态,是不能用这一轮的细胞状态来更新的。

所以我们需要创建一个同样大小的数组,用来存储变化后的值。

创建数组代码如下:

vector<vector<int>> nextBoard(m, vector<int>(n, 0)); // 创建一个新的矩阵来存储下一步的状态

接下来,我们需要计算周围8个格加起来的活细胞数量。但这里要注意边界情况。

8个格子(普通版),边界需要处理,if语句,写起来又臭又长。

ans+= matirex[i-1][j]+matirex[i+1][j]+matirex[i][j-1]+matirex[i][j+1]
      +matirex[i-1][j-1]+matirex[i+1][j+1]+matirex[i+1][j-1]+matirex[i-1][j+1];

  所以不妨设置移动变量 dx,dy.先将x,y进行变化,然后判断越界情况。

    for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) continue; // 跳过当前位置
                int x = i + dx;
                int y = j + dy;
                if (x >= 0 && x < m && y >= 0 && y < n) {//在区域内
                    count += matrix[x][y];
                }
            }
        }

再根据生存规律判断细胞实际存活情况 。

最后将结果复制回数组中。

class Solution {
public:
    int num(vector<vector<int>>& matrix, int i, int j) {
        int count = 0;
        int m = matrix.size();
        int n = matrix[0].size();

        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) continue; // 跳过当前位置
                int x = i + dx;
                int y = j + dy;
                if (x >= 0 && x < m && y >= 0 && y < n) {
                    count += matrix[x][y];
                }
            }
        }

        return count;
    }

    void gameOfLife(vector<vector<int>>& board) {
        int m = board.size();
        int n = board[0].size();

        vector<vector<int>> nextBoard(m, vector<int>(n, 0)); 
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int liveNeighbors = num(board, i, j);

                // 根据规则更新下一步的状态
                if (board[i][j] == 1 && (liveNeighbors == 2 || liveNeighbors == 3)) {
                    nextBoard[i][j] = 1; // 存活状态
                } else if (board[i][j] == 0 && liveNeighbors == 3) {
                    nextBoard[i][j] = 1; // 重生
                } else {
                    nextBoard[i][j] = 0; // 死亡
                }
            }
        }

        // 将下一步状态复制回原矩阵
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                board[i][j] = nextBoard[i][j];
            }
        }
    }
};

复杂度:时间复杂度0(mn),空间复杂度0(mn)。

方法二:使用额外的状态

方法一中O(mn) 的空间复杂度在数组很大的时候内存消耗是非常昂贵的。题目中每个细胞只有两种状态 live(1) 或 dead(0),但我们可以拓展一些复合状态使其包含之前的状态。举个例子,如果细胞之前的状态是 0,但是在更新之后变成了 1,我们就可以给它定义一个复合状态 2。这样我们看到 2,既能知道目前这个细胞是活的,还能知道它之前是死的。

根据生存规律判断细胞实际存活情况,规则修正如下:

规则 1:如果活细胞周围八个位置的活细胞数少于两个,则该位置活细胞死亡。这时候,将细胞值改为 -1,代表这个细胞过去是活的现在死了;

规则 2:如果活细胞周围八个位置有两个或三个活细胞,则该位置活细胞仍然存活。这时候不改变细胞的值,仍为 1

规则 3:如果活细胞周围八个位置有超过三个活细胞,则该位置活细胞死亡。这时候,将细胞的值改为 -1,代表这个细胞过去是活的现在死了。可以看到,因为规则 1 和规则 3 下细胞的起始终止状态是一致的,因此它们的复合状态也一致;

规则 4:如果死细胞周围正好有三个活细胞,则该位置死细胞复活。这时候,将细胞的值改为 2,代表这个细胞过去是死的现在活了。

另外:计数方式也需要改一下,只有当abs(board[x][y]) == 1时,原先才是活的,进行计数

                // 根据规则更新下一步的状态
                if (board[i][j] == 1 && (liveNeighbors < 2 || liveNeighbors > 3)) {
                    board[i][j] = -1; // 存活状态
                } else if (board[i][j] == 0 && liveNeighbors == 3) {
                    board[i][j] = 2; // 重生
                } //其他位置保持不变即可


                //计数方式:
                if (x >= 0 && x < m && y >= 0 && y < n&&(abs(board[x][y]) == 1)) {
                    count += 1;
                }

最后再讲2更改为 1;3更改为0 即可。 

代码如下:

class Solution {
public:
    int num(vector<vector<int>>& matrix, int i, int j) {
        int count = 0;
        int m = matrix.size();
        int n = matrix[0].size();

        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) continue; // 跳过当前位置
                int x = i + dx;
                int y = j + dy;
                if (x >= 0 && x < m && y >= 0 && y < n&&(abs(matrix[x][y]) == 1)) {
                    count += 1;
                }
            }
        }

        return count;
    }

    void gameOfLife(vector<vector<int>>& board) {
        int m = board.size();
        int n = board[0].size();

        //vector<vector<int>> nextBoard(m, vector<int>(n, 0)); // 创建一个新的矩阵来存储下一步的状态

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                int liveNeighbors = num(board, i, j);

               // 根据规则更新下一步的状态
                if (board[i][j] == 1 && (liveNeighbors < 2 || liveNeighbors > 3)) {
                    board[i][j] = -1; // 存活状态
                } else if (board[i][j] == 0 && liveNeighbors == 3) {
                    board[i][j] = 2; // 重生
                } //其他位置保持不变即可

            }
        }

        // 将下一步状态复制回原矩阵
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
               if(board[i][j]>0) board[i][j] = 1;
               else board[i][j] = 0;
            }
        }
    }
};

48. 旋转图像

题目:

给定一个 × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

思路:要求原地修改数组,说明空间复杂度需要为0(1),考虑使用swap,调换数组位置。

常用调换位置方法:

1.中心反转

        swap(matrix[i][j],matrix[j][i]);

        swap(matrix[i][j],matrix[n-j-1][n-i-]);

2.水平翻转 swap(matrix[i][j],matrix[n-i-1][j]);

3.数列翻转 swap(matrix[i][j],matrix[i][n-j-1]);

翻转问题一定注意下标的范围,反转只需要换一半!!!

例如水平和数列 n/2,中心就是j<i

本题研究一下发现只需要中心翻转+数列翻转一下即可

matrix =[[1,2,3],[4,5,6],[7,8,9]]

中心翻转后:[[1,4,7],[2,5,8],[3,6,9]]        swap(matrix[i][j],matrix[j][i]);

数列翻转:[[7,4,1],[8,5,2],[9,6,3]]

 代码:

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n=matrix.size();
        
        for(int i=0;i<n;i++){
            for(int j=0;j<i;j++){
               swap(matrix[i][j],matrix[j][i]);
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n/2;j++){
                swap(matrix[i][j],matrix[i][n-j-1]);
            }
        }

    }
};

73. 矩阵置零

题目:

给定一个 m x n 的矩阵,如果一个元素为 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法

方法一:开一个二维数组

1.一个直观的解决方案是使用  O(mn) 的额外空间,但这并不是一个好的解决方案。

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int>> res(m, vector<int>(n, 1));

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 0) {
                    for (int k = 0; k < n; k++)
                        res[i][k] = 0;
                    for (int k = 0; k < m; k++)
                        res[k][j] = 0;
                }
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrix[i][j] = matrix[i][j] * res[i][j];
            }
        }
    }
};
方法二:创建两个额外的数组来记录哪些行和列需要被置零

一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        vector<int> res_row(m, 1);
        vector<int> res_col(n, 1);

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {

                if (matrix[i][j] == 0) {
                    res_row[i]=0;
                    res_col[j]=0;
                }
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrix[i][j] = matrix[i][j] * res_row[i]*res_col[j];
            }
        }
    }
};
方法三:使用两个标记变量

我们可以用矩阵的第一行和第一列代替方法一中的两个标记数组,以达到 O(1) 的额外空间。但这样会导致原数组的第一行和第一列被修改,无法记录它们是否原本包含 0。因此我们需要额外使用两个标记变量分别记录第一行和第一列是否原本包含 0。

在实际代码中,我们首先预处理出两个标记变量,接着使用其他行与列去处理第一行与第一列,然后反过来使用第一行与第一列去更新其他行与列,最后使用两个标记变量更新第一行与第一列即可。

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        int flag_col0 = false, flag_row0 = false;
        for (int i = 0; i < m; i++) {
            if (!matrix[i][0]) {
                flag_col0 = true;
            }
        }
        for (int j = 0; j < n; j++) {
            if (!matrix[0][j]) {
                flag_row0 = true;
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (!matrix[i][j]) {
                    matrix[i][0] = matrix[0][j] = 0;
                }
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (!matrix[i][0] || !matrix[0][j]) {
                    matrix[i][j] = 0;
                }
            }
        }
        if (flag_col0) {
            for (int i = 0; i < m; i++) {
                matrix[i][0] = 0;
            }
        }
        if (flag_row0) {
            for (int j = 0; j < n; j++) {
                matrix[0][j] = 0;
            }
        }
    }
};


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1560582.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql执行脚本导入表和数据后中文注释乱码解决

本人在使用不同版本下进行操作时&#xff0c;就会出现中文乱码的问题。例如我本地安装mysql8&#xff0c;服务器安装的是mysql5&#xff0c;然后本地连接服务器的mysql后&#xff0c;执行SQL脚本之后发现中文全部乱码 使用工具查看&#xff0c;注释也都是乱码 解决方案 本地…

PyLMKit(9):ChatTable与你的表格聊天,表格问答

功能介绍 与你的结构化数据聊天&#xff1a;支持主流数据库、表格型excel等数据&#xff01; ChatDB&#xff1a;支持数据库问答ChatTable&#xff1a;支持txt,excel,csv等pandas dataframe表格的问答 1.下载安装 pip install pylmkit -U pip install pandasql2.ChatTable实…

百度“超模”、三大开发神器组团出道?李彦宏2024年度演讲提前剧透!

未来程序员会消失吗&#xff1f;一个大模型能适配一切吗&#xff1f;大模型太贵用不起怎么办&#xff1f;AI时代最好用的工具长什么样&#xff1f;——这些行业热议问题&#xff0c;将在两周后得到答案。 4月16日&#xff0c;百度创始人、董事长兼首席执行官李彦宏将在2024百度…

构建安全高效的用户登录系统:登录流程设计与Token验证详解

在当今数字化时代&#xff0c;用户登录系统是几乎所有在线服务的基础。然而&#xff0c;随着网络安全威胁的不断增加&#xff0c;设计一个安全可靠的登录系统变得至关重要。本文将深入探讨用户登录流程的设计原则以及Token验证的实现方式&#xff0c;带您了解如何构建安全高效的…

题目:小蓝的零花钱(蓝桥OJ 3236)

问题描述&#xff1a; 解题思路&#xff1a; 计算每个可以切割的位置的费用(cnt)&#xff0c;从小到大枚举每个切割费用&#xff0c;当切割总费用大于手里的钱时停止&#xff0c;最后枚举的已切割位置总数就是答案。 #include<bits/stdc.h> using namespace std; const …

科学高效备考2024年汉字小达人:历年真题详细解析-古诗文专题

距离2024年第11届汉字小达人比赛还有七个多月的时间&#xff0c;如何利用这段时间有条不紊地备考呢&#xff1f;我的建议是两手准备&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0c;重点是字、词、成语、古诗。阅读理解不需要。②把历年真题刷刷熟&#xff0c…

物料主数据管理难在哪?基于AI算法的数据清洗工具了解一下

引言 数据清洗在处理大量的、不一致的、错误的或者不完整的数据时扮演着至关重要的角色。随着数据量的不断膨胀&#xff0c;有效的数据清洗工具和方法变得尤为重要。 数据清洗作为数据管理和治理的重要组成部分&#xff0c;近年来受到了国家层面的高度重视&#xff0c;并出台了…

Python保留字与obspy安装

保留字&#xff1a; 被编程语言内部定义并保留使用的标识符。Python有33个保留字 andelifimportraiseglobalaselseinreturnnonlocalassertexceptistryTrue breakfinallylambdawhileFalseclassfornotwithNonecontinuefromoryielddefifpassdel 最近在安装obspy时经常&am…

[SpringCloud] Feign Client 的创建 (二) (五)

文章目录 1.自动配置FeignAutoConfiguration2.生成 Feign Client2.1 从Feign Client子容器获取组件2.2 Feign Client子容器的创建2.3 构建Feign Client实例 1.自动配置FeignAutoConfiguration spring-cloud-starter-openfeign 包含了 spring-cloud-openfeign-core FeignAutoCo…

解决echarts xAxis设置type:‘value‘后 x轴有负值的时候 Y轴在0点显示

前提&#xff1a;xAxis设置type:‘value’ 数据&#xff1a;data里面含有负数值&#xff0c;导致Y坐标轴一直在 X&#xff08;0&#xff09;上面显示 解决方案&#xff1a; yAxis里面设置 axisLine: { onZero:false } yAxis:{type: value,name:测试,axisLine: { onZero:false …

Rust 机器学习图形库 petgraph

一、介绍 Petgraph 是一个开源的图数据结构库&#xff0c;提供了非常丰富的图形类型和算法&#xff0c;并且支持将图形以 Graphviz 格式输出&#xff0c;还允许你为图的节点和边赋予任意类型的数据&#xff0c;从而能够灵活地处理和表示复杂的数据关系。 Petgraph 支持边的方…

【Linux多线程】生产者消费者模型

【Linux多线程】生产者消费者模型 目录 【Linux多线程】生产者消费者模型生产者消费者模型为何要使用生产者消费者模型生产者消费者的三种关系生产者消费者模型优点基于BlockingQueue的生产者消费者模型C queue模拟阻塞队列的生产消费模型 伪唤醒情况&#xff08;多生产多消费的…

MySQL数据库----------探索高级SQL查询语句 (二)

目录 一、子查询 1.1多表查询 1.2多层嵌套 1.3 insert语句子查询 1.4update语句子查询 1.5delete语句子查询 1.6EXISTS 1.7子查询&#xff0c;别名as 二、mysql视图 2.1mysql视图介绍 2.2mysql作用场景[图]: 2.3视图功能&#xff1a; 2.4视图和表的区别和联系 区别…

Linux 个人笔记之三剑客 grep sed awk

文章目录 零、预一、grep 文本过滤工具基础篇实战篇 二、sed 字符流编辑器基础篇实战篇 三、awk 文本处理工具基础篇实战篇 四、附xargsuniq & sort基础篇实战篇 cut 零、预 bash 的命令行展开 {} $ echo file_{1..4} file_1 file_2 file_3 file_4$ echo file_{a..d} file_…

【攻防世界】unseping (反序列化与Linux bash shell)

打开题目环境&#xff1a; 1、进行PHP代码审计&#xff0c;通过审计得知需要用到PHP反序列化。找到输出flag的位置为 ping()函数。通过使用 exec() 函数来执行 $ip 并将结果保存在 $result 中&#xff0c;最终输出 $result。 2、接着寻找给 $ip 传参的位置&#xff0c;发现通过…

FastEI论文阅读

前言 研究FastEI有很长时间了&#xff0c;现在来总结一下&#xff0c;梳理一下认知。论文地址&#xff1a;https://www.nature.com/articles/s41467-023-39279-7&#xff0c;Github项目地址&#xff1a;https://github.com/Qiong-Yang/FastEI。 概要 这篇文章做的工作是小分子…

16.面向对象的软件测试技术

主要考点&#xff1a; 1、面向对象相关的基础概念&#xff1b;&#xff08;已经在软件工程的课程中讲过&#xff0c;要熟悉UML图&#xff0c;知道类和类之间的关系&#xff0c;这些知识也可能结合到下午题考察&#xff09; 2、面向对象的软件测试技术&#xff1b;&#xff08;大…

基于单片机汽车超声波防盗系统设计

**单片机设计介绍&#xff0c;基于单片机汽车超声波防盗系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机汽车超声波防盗系统设计概要主要涉及利用超声波传感器和单片机技术来实现汽车的安全防盗功能。以下是对…

辽宁梵宁教育:点亮大学生设计技能之光

辽宁梵宁教育作为专注于设计教育的线上机构&#xff0c;对大学生设计技能的提升和就业前景产生了深远的影响。在当前数字化时代&#xff0c;设计技能已逐渐成为各行各业不可或缺的重要能力&#xff0c;而梵宁教育正是抓住了这一机遇&#xff0c;致力于培养具备创新思维和实践能…

还在问如何入门 Python 爬虫?收藏这篇直接带你上路爬虫!!

“入门”是良好的动机&#xff0c;但是可能作用缓慢。如果你手里或者脑子里有一个项目&#xff0c;那么实践起来你会被目标驱动&#xff0c;而不会像学习模块一样慢慢学习。另外如果说知识体系里的每一个知识点是图里的点&#xff0c;依赖关系是边的话&#xff0c;那么这个图一…