498 对角线遍历
给你一个大小为 m x n 的矩阵 mat ,请以对角线遍历的顺序,用一个数组返回这个矩阵中的所有元素。
很明显这道题最起码的时间复杂度是O(m*n),直接模拟就好。
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
//类似于螺旋数组,找出边界,变方向
int m = mat.size() , n = mat[0].size() , tar = m*n , num = 0;
vector<int> res(tar);
int i = 0 , j = 0;
bool rightUp = 1 ;
while(num < tar){
res[num++] = mat[i][j];
//遍历
if(rightUp){
i--;j++;
}else{
i++;j--;
}
//出界判断
if(i < 0){ i = 0 ; rightUp = 0;}//上出界,右移,行数不变
else if(j < 0){ j = 0 ; rightUp = 1;}//左出界,下移,列数不变
else if(i == m){
if(j < 0){
j++;
}
i = m - 1 ; j++ ;rightUp =1;
}//下出界,右移,行数不变
else if(j == n){
if(i < 0){
i++;
}
j = m - 1 ; i++ ;rightUp =0;
}
}
return res;
}
};
优化:
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
vector<int> res;
int i = 0, j = 0;
bool rightUp = true;
while (res.size() < m * n) {
res.push_back(mat[i][j]);
if (rightUp) {
if (j == n - 1) {
i++;
rightUp = false;
} else if (i == 0) {
j++;
rightUp = false;
} else {
i--;
j++;
}
} else {
if (i == m - 1) {
j++;
rightUp = true;
} else if (j == 0) {
i++;
rightUp = true;
} else {
i++;
j--;
}
}
}
return res;
}
};
566 重塑矩阵
在 MATLAB 中,有一个非常有用的函数 reshape ,它可以将一个 m x n 矩阵重塑为另一个大小不同(r x c)的新矩阵,但保留其原始数据。
给你一个由二维数组 mat 表示的 m x n 矩阵,以及两个正整数 r 和 c ,分别表示想要的重构的矩阵的行数和列数。
重构后的矩阵需要将原始矩阵的所有元素以相同的 行遍历顺序 填充。
如果具有给定参数的 reshape 操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。
reshape()函数比较重要的一点是,首先应该判断是否可以进行重构:
思路:首先检查原始矩阵的元素总数是否等于新矩阵的元素总数。如果原始矩阵的元素数量与目标矩阵的元素数量不匹配,则不能进行重构。
剩余就比较简单,直接遍历整个mat , 所以时间复杂度最低也应该是O(m*n),通过计数判定对应的reshape后的元素的位置就好。
class Solution {
public:
vector<vector<int>> matrixReshape(vector<vector<int>>& mat, int r, int c) {
vector<vector<int>> res(r , vector<int>(c));
int count = 0 , m = mat.size() , n = mat[0].size();
if(r*c != m*n){return mat;}
//行数 为 count / r , 列数 为 count % c
for(int i = 0 ; i < m ; i++){
for(int j = 0 ; j < n ;j++){
int x = count / c , y = count % c;
res[x][y] = mat[i][j];
count++;
}
}
return res;
}
};
官方题解中将i和j都替换为count/n和count %n了。
for (int x = 0; x < m * n; ++x) {
ans[x / c][x % c] = nums[x / n][x % n];
}
48 旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
类似于昨天看到的螺旋矩阵,不断变化边界,并且保证每一轮的规律一致。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
//空间复杂度为O(1)
//虽然知道旋转的规律,i , j---> j ,n - 1 -j行列互换
//但是很明显原地旋转需要一圈一圈的推进,类似于华容道
//拿出一圈的一个,每层从i行移动到n-i-1,一共是要进行n/2次
int n = matrix.size();
for(int i = 0 ; i < n / 2 ; i++){
for(int j = i ; j < n - i - 1 ; j++){
int temp = matrix[i][j];
matrix[i][j] = matrix[n - j - 1][i];
matrix[n - 1 - j][i] = matrix[n - i - 1][n - j - 1];
matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
matrix[j][n - i - 1] = temp;
}
}
}
};
73 矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。
思路:确定零的位置,标记,置零,根据标记的方法分为两类,只写了第2个方法。
第一类:辅助空间通过设置两个分别以 m 和 n为长度的一维行列数组,遍历matrix,如果元素为0,在对应的行列数组中置1,标示这一行/列就需要置零;
第二类:空间复杂度为O(1)使用矩阵的第一行和第一列作为标记来记录哪些行和列需要置零。
a. 首先,遍历第一行和第一列,判定是否有0;
b. 接着就从i = 1 , j= 1开始遍历,如果为0,就令这一行的开头[i][0]或这一列的开头[0][j]为0;
c.置零分为两步: 第一步就是从i = 1 j = 1开始置零只要[i][0] == 0 || [0][j] == 0就置零,,第二步,是通过第一轮判定的第一行第一列是否为0,对其置零。
就是取巧,讲真
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
bool firstRowZero = false, firstColZero = false;
//第一列/行判定是否为0
for (int i = 0; i < m; ++i) {
if (matrix[i][0] == 0) {
firstColZero = true;
break;
}
}
for (int j = 0; j < n; ++j) {
if (matrix[0][j] == 0) {
firstRowZero = true;
break;
}
}
//标记0的位置
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
if (matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
//置零
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
//第一列/行置零
if (firstRowZero) {
for (int j = 0; j < n; ++j) {
matrix[0][j] = 0;
}
}
if (firstColZero) {
for (int i = 0; i < m; ++i) {
matrix[i][0] = 0;
}
}
}
};