问题描述
给定一个矩阵,假设为n * n的,我们这个矩阵里有若干个数字为1的元素。其他地方的元素值则不为1. 现在需要我们提供一个方法将里面为1的元素所在的行和列都设置成1. 同时要求算法的空间复杂度为O(1)。
分析
这个问题看起来有点容易让人混淆,因为如果我们从前往后这么一行一行的去遍历时,如果碰到一个为1的元素就直接将它所在行和列都设置成1的话。相当于将后面要遍历的一些元素也变成了1,这样我们就没法判断这些元素是本来为1的还是后来被设置成1的。而且,因为有限的空间复杂度我们不能记录下来每个为1的元素的位置信息。
我们以下面的图为例,假定有一个矩阵,它里面包含的1元素如下:
因为在图中只有第2行,第3行和第5行有元素分别为1,那么按照前面设置的思路,最后被设置成的结果应该是这样的:
而如果我们当时碰到一个1元素就直接将它本行或者本列后面的部分置1的话,我们后面遍历到的时候就会产生问题,如下图:
在我们标红的这个地方,如果实现被设置成了1,后面因为没法判断,就会将整个矩阵都置成1了。
所以说,这种原来的思路就有问题。
标记和设置
在讨论这个问题的时候,当时因为受到前面这个思路的影响,可以说被带到沟里去了。其实我们用标记和设置的这个思路来考虑的话,就很好办了。
我们这样来看,既然我们每碰到一个元素,就要将它所在行和列都设置为1, 而为了不影响它后面的遍历,我们肯定不能去修改它后面的元素的值。另外,我们在一个矩阵里,如何去确定一个元素的位置呢?其实很简单,就和二维坐标一样,只要能够确定它所在的行号和列号就可以了。那么如果我们知道一个元素为1的时候,我们就将它所在的元素的行的第一个元素设置为1并将它所在列的第一个元素设置为1。这样不就相当于我们画一些方格的时候给打的点吗?而且有了这些点我们不就可以确定它们后面所画的线了吗?这样也不会对后面的修改造成任何混淆。
依然以前面的图为例,我们在碰到第一个为1的元素时,所要做的事就是设置它所在的行和列的第一个元素,如下图:
这个标红的两个点表示所在的行和列以后要设置为1. 按照这样的思路,我们第一回遍历完整个矩阵之后,得到如下的一个标记结果:
ok,有了这个图我们后面该怎么办呢?其实很简单了,我们就是遍历第一行和第一列,将里面为1的元素对应的行或者列设置为1。当然,在遍历的时候,比如说第一行的时候,我们还有一个特殊的情况要注意,就是假如我们矩阵里m[0][0]的元素为1,我们是不是要将它所在的列置为1呢?因为对应的是第一列,如果一开始我们就将它给设置了的话就破坏了原来设置的结果。所以针对这个特殊的情况,我们需要先跳过,在将后面的所有元素都设置好了之后再回过头来处理它,这样就没问题了。
现在我们来写一个代码的实现,这里主要分为两个部分,第一个是遍历数组设置第一行和第一列的标点元素,第二个是遍历第一行和第一列,然后将对应的行和列标注出来,然后再来判断一下最左上角的元素。
第一部分的实现如下:
void mark(int[][] m, int n) { for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) { if(m[i][j] == 1) { m[0][j] = 1; m[i][0] = 1; } } }
方法很简单,做个标记。
第二个部分的代码:
public void set(int[][] m, int n) { for(int i = 1; i < n; i++) { //注意这里i取从1开始,故意跳过m[0][0]元素。 if(m[0][i] == 1) { setColumn(m, n, i); } if(m[i][0] == 0) { setRow(m, n, i); } } if(m[0][0] == 1) { setRow(m, n, 0); setColumn(m, n, 0); } }
而setRow, setColumn这两个方法的实现只要注意一点,不要从它们这一行第一个元素开始设置就行了。它们的实现如下:
void setColumn(int[][] m, int n, int col) { for(int i = 1; i < n; i++) m[i][col] = 1; } void setRow(int[][] m, int n, int row) { for(int i = 1; i < n; i++) m[row][i] = 1; }
总结
这种问题并不难,有的时候就是要看自己分析的时候思路是不是清晰。当然,这种问题和刷题党的应对手段差不多。鸟儿大了,什么样的林子没见过?有点考核人思考能力的意义,但是并不大。
相关推荐
如果一个实对称矩阵可以通过正交矩阵的乘积转换为对角矩阵,我们就说它可对角化。对角化的过程有助于简化问题,因为它把矩阵的运算转化为简单的标量乘法。在09年的试题中,可能会考察如何找到这样的正交矩阵。 ...
矩阵补全的基本思想是,假设一个矩阵虽然部分观测缺失,但其本质上是低秩的。也就是说,尽管矩阵的维度可能很高,但它可以通过较小数量的独立因素(即秩)来表示。这种低秩假设通常在实际问题中是合理的,例如在推荐...
在搜索过程中,每当访问到一个新的顶点,就更新可达性矩阵,标记该顶点可以从当前搜索路径上的顶点到达。 4. 更新矩阵:对于有向图,需要多次迭代,每次选择一个未被访问过的顶点作为新的起点,直到所有顶点都被...
邻接矩阵是一个方阵,其中的元素表示图中节点之间的连接关系。如果节点i与节点j之间存在边,则邻接矩阵的[i,j]位置上的值为1(或者非零值,具体取决于是否考虑边的权重),反之则为0。 标题“邻接矩阵求可达矩阵...
根据给定的信息,本文将详细解释如何使用C++编程语言编写一个程序来寻找矩阵中的鞍点。首先,我们将介绍什么是鞍点以及它在数学和计算机科学中的应用;然后,逐步解析给定代码,并对其中涉及的关键概念和技术进行...
这个矩阵描述了DFA的所有状态以及在读取特定字符时从一个状态转移到另一个状态的规则。矩阵的行代表当前状态,列代表输入字符,而每个元素表示对应状态下读取该字符后的目标状态。这种形式化表示使得我们可以通过...
矩阵的大小通常由行数(M)和列数(N)定义,例如一个3*4矩阵表示有3行4列的元素。 此矩阵生成工具的界面设计简洁明了,用户只需输入M和N的值,即可自定义矩阵的大小。对于特定的标记用途,用户可以在生成的矩阵上...
本文档将详细介绍一个基于Java语言实现的矩阵相乘算法。该算法通过控制台程序的形式,实现了用户交互输入矩阵的行数与列数,并自动生成相应的二维数组进行相乘操作。程序能够处理不同大小的矩阵,并在不满足矩阵相乘...
在这个问题中,我们要讨论如何使用C++来实现对可达性矩阵的级别划分。 可达性矩阵是一个二元矩阵,其中的每个元素表示系统中的两个组件之间是否存在直接或间接的连接。0表示没有连接,1表示存在连接。级别划分的...
在数学和计算机科学中,矩阵分解是解决众多计算问题的核心技术,它将一个复杂的矩阵转换为更简单、更易于处理的组成部分。本资料提供了一套完整的矩阵分解代码,使用MATLAB编程语言实现,包含了LU分解、QR分解、...
% 假设我们有一个名为corr_matrix的相关系数矩阵 corr_matrix = corr(data); % 绘制色块图 imagesc(corr_matrix) colormap('cool') % 使用冷色调 colorbar % 添加颜色条 axis square % 使单元格面积相等 ...
这种方法需要一个约定来标记数组的结束,比如文档中使用"-1"作为标记。 ### 稀疏矩阵运算实现 在稀疏矩阵的运算中,最常见的是加法和减法。由于大部分元素为零,所以稀疏矩阵的加法和减法运算与普通矩阵不同,不是...
在OOPN的性能分析中,关联矩阵是一种重要的分析工具,用于处理资源分配、系统生产率控制等问题。传统的Petri网中,关联矩阵可以通过简单的权重计算得出,但在OOPN中,由于弧上传递的是对象,无法直接用对象来构建...
矩阵论是线性代数的一个重要分支,主要研究矩阵的性质和运算,它在现代数学、物理学、工程学以及计算机科学等领域有着广泛的应用。清华大学作为中国顶尖的高等学府,其数学系的矩阵论课程自然备受关注。这些课件旨在...
SWOT分析与波士顿矩阵的对比分析可以涉及多个方面: 1. 分析维度的不同:SWOT分析是对组织的宏观层面评估,它关注的是组织可以控制的内部因素(优势和劣势),以及组织不能控制的外部因素(机会和威胁)。而波士顿...
波士顿矩阵的核心思想是,一个公司应该拥有四种不同类型的产品或业务单位,每种类型都有不同的特征和资源需求。 2. 市场增长率和相对市场份额的定义 市场增长率是指产品市场销售量的增长速度,反映了市场的吸引力和...
Hessian矩阵是图像处理和计算机视觉领域中一个重要的数学工具,尤其在特征检测和结构分析中扮演着关键角色。在本项目中,它被应用于血管增强,这是一个在医学成像和图像分析中常见的任务,目的是突出血管结构,以...
- **按键标识**:每个按键都有一个唯一的标识符,如S1、S2等,这些标识符按照矩阵形式排列,形成一个4x4的矩阵。 - **行线和列线**:可以看到,行线标记为0、1、2、3,列线同样标记为0、1、2、3。行线和列线交叉点即...
以波士顿矩阵和安索夫矩阵为例,介绍数据分析基础思维的矩阵思维,即二元关系思维。用Excel演示。来源是“数据分析不是个事儿”的微信公众号文章,做了简单标记的md档。