文章目录
前言
欢迎大家关注我的公众号:菜鸡哪里出来,以获取更多资讯
今天算法的内容是:矩阵
本题解旨在用通俗易懂的语言来讲解课后作业中的难题,简单题会略过
题解对应章节
算法零基础100讲(英雄哥著)–第三讲
第一题:1582. 二进制矩阵中的特殊位置
难度 : ★★
题目描述
给你一个大小为 rows x cols 的矩阵 mat,其中 mat[i][j] 是 0 或 1,请返回 矩阵 mat 中特殊位置的数目 。
特殊位置的定义:如果 mat[i][j] == 1 并且第 i 行和第 j 列中的所有其他元素均为 0(行和列的下标均 从 0 开始 ),则位置 (i, j) 被称为特殊位置
算法思路
总体思路:简单的模拟问题,根据题目要求进行穷举即可。
具体来说,就是以如下三个条件进行筛选:①特殊位置的元素具备该行所有元素之和为1②该列所有元素之和为1③该元素为1
源码剖析
class Solution {
public:
int numSpecial(vector<vector<int>>& mat) {
int rows = mat.size();
int cols = mat[0].size();
int res=0;
vector<int> col(cols),row(rows);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
row[i] += mat[i][j]; //求每个元素所在每行之和
col[j] += mat[i][j]; //求每个元素所在每列之和
}
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if ((mat[i][j]==1) && (row[i]==1) && (col[j] == 1))//进行筛选
{
res++;
}
}
}
return res;
}
};
第二题:48. 旋转图像
难度 : ★★
题目描述
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
算法思路
相信去看这个题目官方题解和高赞题解的小伙伴,肯定会疑惑于什么逐层平移,什么变换公式,难记忆不说,看懂都很费劲。但其实有简单的线性代数基础就可以轻松秒杀,还能得出通用结论
观察所给的测试样例不难观察出如下的结论
矩阵顺时针旋转90° == 矩阵先进行转置,后进行水平翻转
源码剖析
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int rows = matrix.size();
int cols = matrix[0].size();
//矩阵转置,旋转90°等于先转置再水平翻转
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < i; j++) //①
{
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}
//矩阵水平翻转
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < (cols+1)/2; j++) //②
{
int tmp = matrix[i][j];
matrix[i][j] = matrix[i][cols - 1 -j];
matrix[i][cols - 1 -j] = tmp;
}
}
}
};
-
1、第一处注释要特意注意列的上界,因为矩阵转置是行变列,列变行。
故转置可进一步细化为,矩阵各元素沿主对角线翻转,所以只需要进行矩阵下三角翻转到上三角即可(对于方阵) -
2、为①③条件的实现
第三题:867. 转置矩阵
难度 : ★★
题目描述
给你一个二维整数数组 matrix, 返回 matrix 的 转置矩阵 。
矩阵的 转置 是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引。
算法思路
本题给予另一种转置的思路,在没有限定必须原地转置的情况下,构造一个新矩阵也为一种特别简单的方法,当然要注意此时的ij范围。
源码剖析
class Solution {
public:
vector<vector<int>> transpose(vector<vector<int>>& matrix) {
vector<vector<int>> res(matrix[0].size(),vector<int>(matrix.size()));
for (int i = 0; i < matrix.size(); i++)
{
for (int j = 0; j <matrix[0].size(); j++)//①
{
res[j][i] = matrix[i][j];
}
}
return res;
}
};
- 1、此处因为是新矩阵填数,所以j上界为矩阵的列数
第四题:1886. 判断矩阵经轮转后是否一致
难度 : ★★
题目描述
给你两个大小为 n x n 的二进制矩阵 mat 和 target 。现 以 90 度顺时针轮转 矩阵 mat 中的元素 若干次 ,如果能够使 mat 与 target 一致,返回 true ;否则,返回 false 。
算法思路
本题应用第二题的结论进行矩阵90°旋转,显然可知,一个矩阵旋转4次后就会恢复原样;故四次旋转内能相等即复合要求,否则返回false
源码剖析
cpp
class Solution {
public:
bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
bool res =false;
for (int k = 0; k < 4; k++)
{
for (int i = 0; i < mat.size(); i++)
{
for (int j = 0; j < i; j++)
{
swap(mat[i][j],mat[j][i]);
}
}
for (int i = 0; i < mat.size(); i++)
{
for (int j = 0; j < (mat[0].size()+1)/2; j++)
{
swap(mat[i][j],mat[i][mat[0].size()-j-1]);
}
}
if (mat == target)
{
res = true;
break;
}
}
return res;
}
};class Solution {
public:
bool findRotation(vector<vector<int>>& mat, vector<vector<int>>& target) {
bool res =false;
for (int k = 0; k < 4; k++)//①
{
for (int i = 0; i < mat.size(); i++)//②
{
for (int j = 0; j < i; j++)
{
swap(mat[i][j],mat[j][i]);
}
}
for (int i = 0; i < mat.size(); i++)//③
{
for (int j = 0; j < (mat[0].size()+1)/2; j++)
{
swap(mat[i][j],mat[i][mat[0].size()-j-1]);
}
}
if (mat == target)//④
{
res = true;
break;
}
}
return res;
}
};
- 1、循环模拟四次旋转
- 2、进行矩阵转置
- 3、进行水平翻转,完成一次90°旋转
- 4、若相等则退出循环,返回值
第五题:1260. 二维网格迁移
难度 : ★★
题目描述
给你一个 m 行 n 列的二维网格 grid 和一个整数 k。你需要将 grid 迁移 k 次。
每次「迁移」操作将会引发下述活动:
位于 grid[i][j] 的元素将会移动到 grid[i][j + 1]。
位于 grid[i][n - 1] 的元素将会移动到 grid[i + 1][0]。
位于 grid[m - 1][n - 1] 的元素将会移动到 grid[0][0]。
请你返回 k 次迁移操作后最终得到的 二维网格。
算法思路
本题是一个简单的模拟问题,即从后往前进行交换矩阵每一列,再从下往上交换第一列的元素
源码剖析
class Solution {
public:
vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {
for (int i = 0; i < k; i++) //①
{
for (int i = 0; i < grid.size(); i++)
{
for (int j = grid[0].size()-1; j >0; j--)//②
{
swap(grid[i][j-1],grid[i][j]);
}
}
for (int i = grid.size()-1; i >0 ; i--)//③
{
swap(grid[i][0],grid[i-1][0]);
}
}
return grid;
}
};
- 1、变换k次迁移
- 2、从后往前进行变换每一列
- 3、从下往上交换第一列的元素
第六题:1260. 二维网格迁移
难度 : ★★★
题目描述
本章节的压轴题来啦!
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
算法思路
首先设定上下左右边界
其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界
判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案
若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理
不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案
源码剖析
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> res;
if (matrix.size() == 0)
{
return res;
}
int upper =0,down = matrix.size()-1,left =0,right = matrix[0].size()-1;
while (true)
{
for (int i = left; i <= right; i++)
{
res.push_back(matrix[upper][i]);
}
if (++upper > down)
{
break;
}
for (int i = upper; i <= down; i++)
{
res.push_back(matrix[i][right]);
}
if (--right < left)
{
break;
}
for (int i = right; i >= left ; i--)
{
res.push_back(matrix[down][i]);
}
if (--down < upper)
{
break;
}
for (int i = down; i >= upper;i--)
{
res.push_back(matrix[i][left]);
}
if (++left > right)
{
break;
}
}
return res;
}
};