Leetcode Hot 100 —— 矩阵

73. 矩阵置零


思路与解法

1、标记阶段:遍历整个矩阵,遇到 0 元素时,记录下它所在的行和列(用两个布尔数组 row 和 col 分别标记)。

2、置零阶段:再次遍历矩阵,对于每个元素,检查其所在行或列是否被标记,如果是则将其置零。

cpp 复制代码
class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int m = matrix.size();   //获取矩阵的行数
        int n = matrix[0].size();//获取矩阵的列数
        //创建两个标记数组:row用于标记需要置零的行,col用于标记需要置零的列
        vector<int> row(m);
        vector<int> col(n);
        //第一次遍历:扫描整个矩阵,记录哪些行和列包含0
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!matrix[i][j]){
                    row[i]=true;
                    col[j]=true;                    
                }
            }
        }
        //第二次遍历:根据标记数组,将对应行和列的元素置零
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(row[i]||col[j]){
                    matrix[i][j]=0;
                }
            }
        } 
    }
};

ACM:

cpp 复制代码
#include <vector>
#include <iostream>
using namespace std;

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

int main(){
    int m, n;
    cin >> m >> n;
    vector<vector<int>> matrix(m,vector<int>(n));

    for(int i=0;i<m;i++)
      for(int j=0;j<n;j++)
         cin>>matrix[i][j];
    
    Solution sol;
    sol.setZeroes(matrix);

    for(auto& row:matrix){
        bool first=true;
            for(int num:row){
                if(!first) cout<<" ";  //如果不是第一个,先输出空格
                cout<<num;
                first=false;
            }
            cout<<endl;
    }
}

54.螺旋矩阵

思路与解法

本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。一定要明确好边界!!

核心是模拟螺旋遍历矩阵的过程。遍历方式如下:

从左到右遍历上边界

从上到下遍历右边界

从右到左遍历下边界(如果仍然存在)

从下到上遍历左边界(如果仍然存在)

然后不断缩小边界范围,直到遍历完整个矩阵。

代码使用的是左闭右闭区间。即每一圈的遍历范围包括边界上的所有元素,循环条件使用 <= 来包含起始和结束位置。遍历完一条边后立即收缩对应边界,确保下一圈不会重复访问已处理的元素。

算法设计

我们可以定义四个变量来表示边界:

top表示上边界,bottom表示下边界

left表示左边界,right表示右边界

遍历过程中按照顺时针方向进行:

① 遍历top行,从left到right,然后top++

② 遍历right列,从top到bottom,然后right- -

③ 如果仍然有bottom行,则从right到left遍历该行,bottom- -

④ 如果仍然有left列,则从bottom到top遍历该列,left++

不断重复上述过程,直到所有元素都被访问。

为什么需要这两个 if?

在每一圈的遍历中,我们依次处理四条边:

上边:从左到右(一定存在)

右边:从上到下(一定存在,因为至少有一行一列)

下边:从右到左(可能不存在)

左边:从下到上(可能不存在)

理清楚这4条边用什么变量即可。先画个图!!

核心代码:

cpp 复制代码
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> results;
        if(matrix.empty()||matrix[0].empty()) return results;
        int m = matrix.size();
        int n = matrix[0].size();
        int top = 0,bottom = m-1;
        int left =0,right = n-1;

        while(top<=bottom && left<=right){
                for(int i=left;i<=right;i++){
                    results.push_back(matrix[top][i]);
                }
                top++;
                for(int i=top;i<=bottom;i++){
                    results.push_back(matrix[i][right]);               
                }
                right--;

                if(top<=bottom){
                    for(int i=right;i>=left;i--){
                    results.push_back(matrix[bottom][i]);
                    }
                    bottom--;
                }

                if(left<=right){
                    for(int i=bottom;i>=top;i--){
                    results.push_back(matrix[i][left]);
                    }
                    left++;    
                }
            }
          return results;
        }
};

【注】

1、为何下两种情况要用if?

当矩阵只有一行(top == bottom)时,遍历完上边(即整行)后,top 增加,导致 top > bottom。此时下边与上边其实是同一行,如果继续遍历下边,就会把这一行的元素再反向遍历一遍,造成重复。

同样,当矩阵只有一列(left == right)时,遍历完上边和右边后,right 减少,导致 left > right。此时左边与右边其实是同一列,如果继续遍历左边,也会重复访问该列的元素。

因此,必须在遍历下边之前检查是否还有多行(top <= bottom),在遍历左边之前检查是否还有多列(left <= right)。这两个条件确保了在边界收缩后,我们只遍历实际存在的边。

注意 bottom--;left++; 要放在if里面!!!

2、统一左闭右闭,即for循环里面都取=(<=、>=)!!

48. 旋转图像

思路与解法

先转置,然后水平翻转!!!

核心代码:

cpp 复制代码
class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n=matrix.size();
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;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-1-j]);
            }
        }      
    }
};

【注】

1、 for (int j = i + 1; j < n; j++) {

内层循环从 j = i + 1开始,只处理上三角(i < j),避免重复交换,保证每个非对角线元素只被交换一次。

2、for (int j = 0; j < n / 2; j++) {

只需要遍历每一行的左半部分,因为右半部分会在交换时自动被处理。

ACM:

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;


class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n=matrix.size();
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;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-1-j]);
            }
        }      
    }
};

int main(){
    int n;
    cin>>n;
    vector<vector<int>> matrix(n,vector<int>(n));

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>matrix[i][j];
        }
    }

    Solution sol;
    sol.rotate(matrix);

    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(j>0) cout<<" ";
            cout<<matrix[i][j];
        }
        cout<<endl;
    }
    return 0;
}

【注】

1、 if(j>0) cout<<" ";

注意是j>0!!

240.搜索二维矩阵 II

思路与解法

本题要求高效搜索,最优解法为"Z 字型查找",时间复杂度 O(m + n)。

核心思路:

由于矩阵行递增、列递增,我们可以从右上角出发,往左下移动

如果当前值 matrix[i][j] == target,返回 true。

如果当前值 > target,左移(j- -) 。

如果当前值 < target,下移(i++)。

若超出矩阵边界,则返回 false。

核心代码:

cpp 复制代码
class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size(),n= matrix[0].size();
        int i=0,j=n-1;

        while(i<m&&j>=0){
            if(matrix[i][j]==target) return true;
            else if(matrix[i][j]>target) j--;
            else i++;
        }
        return false;
    }
};

【注】

1、while (i < m && j >= 0)

确保行索引不超出下边界(0...m-1),列索引不超出左边界(0...n-1)。

ACM:

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m = matrix.size(),n= matrix[0].size();
        int i=0,j=n-1;

        while(i<m&&j>=0){
            if(matrix[i][j]==target) return true;
            else if(matrix[i][j]>target) j--;
            else i++;
        }
        return false;
    }
};

int main(){
    int m,n,target;
    cin>>m>>n;
    vector<vector<int>> matrix(n,vector<int>(n));
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            cin>>matrix[i][j];
        }
    }

    cin>>target;

    Solution sol;
    cout<<(sol.searchMatrix(matrix,target)?"true":"false")<<endl;

    return 0;
}
相关推荐
一叶落4382 小时前
LeetCode 149. 直线上最多的点数(C语言详解 | 斜率 + 最大共线点)
数据结构·c++·算法·leetcode
逆境不可逃2 小时前
LeetCode 热题 100 之 152. 乘积最大子数组 416. 分割等和子集 32. 最长有效括号 62. 不同路径
算法·leetcode·职场和发展
一叶落4382 小时前
LeetCode 136. 只出现一次的数字(C语言详解 | 哈希表 + 排序 + 位运算)
c语言·数据结构·算法·leetcode·哈希算法·散列表
逆境不可逃2 小时前
【从零入门23种设计模式19】行为型之观察者模式
java·开发语言·算法·观察者模式·leetcode·设计模式·动态规划
月明长歌3 小时前
【码道初阶-Hot100】 LeetCode 49. 字母异位词分组:从排序哈希到分组映射,彻底讲透为什么排序后可以作为同一组的标识
算法·leetcode·哈希算法
big_rabbit05023 小时前
[算法][力扣242]有效的字母异位词
java·前端·leetcode
小年糕是糕手3 小时前
【35天从0开始备战蓝桥杯 -- Day4】
数据结构·c++·算法·leetcode·蓝桥杯
无尽的罚坐人生3 小时前
hot 100 98. 验证二叉搜索树
算法·leetcode
美好的事情能不能发生在我身上3 小时前
Leetcode热题100中的:矩阵专题
算法·leetcode·矩阵