hot100——矩阵

矩阵置零

73. 矩阵置零 - 力扣(LeetCode)

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

示例 1:

复制代码
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
复制代码
输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

解法及思路

用第一行和第一列做标记

核心思想:

复制代码
不用额外数组,直接用矩阵的第一行和第一列来标记

matrix[i][0] = 0  →  第i行要置零
matrix[0][j] = 0  →  第j列要置零

但是问题来了:

复制代码
第一行和第一列本身也可能要置零
如果用它们做标记,就分不清:
  matrix[0][j]=0 是"原本就是0"还是"标记"?

所以需要额外两个变量:

java 复制代码
boolean firstRowZero = false;  // 第一行本身是否要置零
boolean firstColZero = false;  // 第一列本身是否要置零

举例:

matrix = [

1, 2, 3, 4,

5, 0, 7, 8,

9, 10, 0, 12,

13, 14, 15, 16

]

第1步:检查第一行是否有0

第一行:[1, 2, 3, 4]

复制代码
没有0 → firstRowZero = false

第2步:检查第一列是否有0

第一列:[1, 5, 9, 13]

复制代码
没有0 → firstColZero = false

第3步:用第一行/列标记内层

遍历内层:

复制代码
i=1, j=1: matrix[1][1]=0
  matrix[1][0] = 0  ← 标记第1行
  matrix[0][1] = 0  ← 标记第1列

i=1, j=2: matrix[1][2]=7,不是0
i=1, j=3: matrix[1][3]=8,不是0

i=2, j=1: matrix[2][1]=10,不是0
i=2, j=2: matrix[2][2]=0
  matrix[2][0] = 0  ← 标记第2行
  matrix[0][2] = 0  ← 标记第2列

i=2, j=3: matrix[2][3]=12,不是0

i=3, j=1: matrix[3][1]=14,不是0
i=3, j=2: matrix[3][2]=15,不是0
i=3, j=3: matrix[3][3]=16,不是0

标记后矩阵:

复制代码
[1,  0,  0,  4]   ← matrix[0][1]=0, matrix[0][2]=0
[0,  0,  7,  8]   ← matrix[1][0]=0
[0,  10, 0,  12]  ← matrix[2][0]=0
[13, 14, 15, 16]

第一行:标记了第1列和第2列

第一列:标记了第1行和第2行

第4步:根据标记置零内层

遍历内层:

复制代码
i=1, j=1: matrix[1][0]=0 → 置0
  矩阵:[1,0,0,4] [0,0,7,8] [0,10,0,12] [13,14,15,16]

i=1, j=2: matrix[0][2]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,8] [0,10,0,12] [13,14,15,16]

i=1, j=3: matrix[1][0]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,10,0,12] [13,14,15,16]

i=2, j=1: matrix[2][0]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,12] [13,14,15,16]

i=2, j=2: matrix[2][0]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,12] [13,14,15,16]

i=2, j=3: matrix[0][2]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,0] [13,14,15,16]

i=3, j=1: matrix[3][0]=13, matrix[0][1]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,0] [13,0,15,16]

i=3, j=2: matrix[0][2]=0 → 置0
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,0] [13,0,0,16]

i=3, j=3: matrix[3][0]=13, matrix[0][3]=4 → 不置零
  矩阵:[1,0,0,4] [0,0,0,0] [0,0,0,0] [13,0,0,16]

置零后矩阵:

复制代码
[1,  0,  0,  4]
[0,  0,  0,  0]
[0,  0,  0,  0]
[13, 0,  0,  16]

第5步:处理第一行

firstRowZero = false → 不处理

复制代码
[1,  0,  0,  4]
[0,  0,  0,  0]
[0,  0,  0,  0]
[13, 0,  0,  16]

第6步:处理第一列

firstColZero = false → 不处理

复制代码
[1,  0,  0,  4]
[0,  0,  0,  0]
[0,  0,  0,  0]
[13, 0,  0,  16]

最终结果

复制代码
[1,  0,  0,  4]
[0,  0,  0,  0]
[0,  0,  0,  0]
[13, 0,  0,  16] ✅
java 复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        boolean firstRowZero = false;
        boolean firstColZero = false;
        
        // 第1步:检查第一行
        for (int j = 0; j < n; j++) {
            if (matrix[0][j] == 0) firstRowZero = true;
        }
        
        // 第2步:检查第一列
        for (int i = 0; i < m; i++) {
            if (matrix[i][0] == 0) firstColZero = true;
        }
        
        // 第3步:标记
        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;  // 标记列
                }
            }
        }
        
        // 第4步:置零
        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;
                }
            }
        }
        
        // 第5步:处理第一行
        if (firstRowZero) {
            for (int j = 0; j < n; j++) matrix[0][j] = 0;
        }
        
        // 第6步:处理第一列
        if (firstColZero) {
            for (int i = 0; i < m; i++) matrix[i][0] = 0;
        }
    }
}

螺旋矩阵

54. 螺旋矩阵 - 力扣(LeetCode)

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例 1:

复制代码
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]

示例 2:

复制代码
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]

解法及思路

边界收缩

用四个边界

复制代码
top    = 0        (上边界)
bottom = m - 1    (下边界)
left   = 0        (左边界)
right  = n - 1    (右边界)

按顺序遍历:

复制代码
1. 从左到右:top 行,left → right
2. 从上到下:right 列,top → bottom
3. 从右到左:bottom 行,right → left
4. 从下到上:left 列,bottom → top

每遍历完一条边,收缩对应边界

输入:

复制代码
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

初始边界:

复制代码
top=0, bottom=2, left=0, right=2

第1步:从左到右(top行)

复制代码
top=0, left→right: 1, 2, 3
结果:[1, 2, 3]
top++ → top=1

第2步:从上到下(right列)

复制代码
right=2, top→bottom: 6, 9
结果:[1, 2, 3, 6, 9]
right-- → right=1

第3步:从右到左(bottom行)

复制代码
bottom=2, right→left: 8, 7
结果:[1, 2, 3, 6, 9, 8, 7]
bottom-- → bottom=1

第4步:从下到上(left列)

复制代码
left=0, bottom→top: 4
结果:[1, 2, 3, 6, 9, 8, 7, 4]
left++ → left=1

第5步:从左到右(top行)

复制代码
top=1, left→right: 5
结果:[1, 2, 3, 6, 9, 8, 7, 4, 5]
top++ → top=2

结束:top=2 > bottom=1,退出循环

结果:[1, 2, 3, 6, 9, 8, 7, 4, 5] ✅

java 复制代码
class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> result = new ArrayList<>();
        if (matrix == null || matrix.length == 0) return result;
        
        int top = 0, bottom = matrix.length - 1;
        int left = 0, right = matrix[0].length - 1;
        
        while (top <= bottom && left <= right) {
            // 1. 从左到右
            for (int j = left; j <= right; j++) {
                result.add(matrix[top][j]);
            }
            top++;
            
            // 2. 从上到下
            for (int i = top; i <= bottom; i++) {
                result.add(matrix[i][right]);
            }
            right--;
            
            // 3. 从右到左(需要判断是否还有行)
            if (top <= bottom) {
                for (int j = right; j >= left; j--) {
                    result.add(matrix[bottom][j]);
                }
                bottom--;
            }
            
            // 4. 从下到上(需要判断是否还有列)
            if (left <= right) {
                for (int i = bottom; i >= top; i--) {
                    result.add(matrix[i][left]);
                }
                left++;
            }
        }
        
        return result;
    }
}

旋转图像

48. 旋转图像 - 力扣(LeetCode)

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

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

示例 1:

复制代码
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 2:

复制代码
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]

解法及思路

先转置,再反转

顺时针旋转 90 度 = 转置 + 每行反转

复制代码
第1步:转置(行列互换)
[1, 2, 3]      [1, 4, 7]
[4, 5, 6]  →   [2, 5, 8]
[7, 8, 9]      [3, 6, 9]

第2步:每行反转
[1, 4, 7]      [7, 4, 1]
[2, 5, 8]  →   [8, 5, 2]
[3, 6, 9]      [9, 6, 3] ✅

输入:

复制代码
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

第1步:转置

转置就是 matrix[i][j] 和 matrix[j][i] 交换。

复制代码
i=0, j=1: 交换 matrix[0][1] 和 matrix[1][0]
  2 和 4 交换
  [1, 4, 3]
  [2, 5, 6]
  [7, 8, 9]

i=0, j=2: 交换 matrix[0][2] 和 matrix[2][0]
  3 和 7 交换
  [1, 4, 7]
  [2, 5, 6]
  [3, 8, 9]

i=1, j=2: 交换 matrix[1][2] 和 matrix[2][1]
  6 和 8 交换
  [1, 4, 7]
  [2, 5, 8]
  [3, 6, 9]

转置完成!

第2步:每行反转

复制代码
第0行:[1, 4, 7] → [7, 4, 1]
第1行:[2, 5, 8] → [8, 5, 2]
第2行:[3, 6, 9] → [9, 6, 3]

结果:
[7, 4, 1]
[8, 5, 2]
[9, 6, 3] ✅
java 复制代码
class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        
        // 第1步:转置
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {// 注意:j 从 i+1 开始,只遍历上三角,避免重复交换
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        
        // 第2步:每行反转
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n / 2; j++) {// 只遍历前一半
                int temp = matrix[i][j];
                matrix[i][j] = matrix[i][n - 1 - j];
                matrix[i][n - 1 - j] = temp;
            }
        }
    }
}

搜索二维矩阵||

240. 搜索二维矩阵 II - 力扣(LeetCode)

编写一个高效的算法来搜索 m xn 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

复制代码
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true

示例 2:

复制代码
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

解法及思路

从右上角开始

关键:右上角的元素有特殊性质。

复制代码
右上角:15

比15小的:左边所有元素(同一行左边)
比15大的:下边所有元素(同一列下边)

所以:
target < 15 → 往左走(排除这一列)
target > 15 → 往下走(排除这一行)
target == 15 → 找到

为什么从右上角?

复制代码
因为右上角是"这一行最大,这一列最小"
可以明确判断往哪走

输入:

复制代码
[1,  4,  7,  11, 15]
[2,  5,  8,  12, 19]
[3,  6,  9,  16, 22]
[10, 13, 14, 17, 24]
[18, 21, 23, 26, 30]
target = 5

从右上角开始:

复制代码
初始:row=0, col=4
matrix[0][4] = 15

15 > 5 → 往左走,col=3
matrix[0][3] = 11

11 > 5 → 往左走,col=2
matrix[0][2] = 7

7 > 5 → 往左走,col=1
matrix[0][1] = 4

4 < 5 → 往下走,row=1
matrix[1][1] = 5

5 == 5 → 找到!✅
java 复制代码
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m=matrix.length;
        int n=matrix[0].length;
        int row = 0;       // 从右上角开始
        int col = n - 1;
        while(row<m&&col>=0){
            if(matrix[row][col]==target){
                return true;
            }else if(matrix[row][col]>target){
                col--;//大了,往左
            }else{
                row++;//小了,往下
            }
        }
        return false;
    }
}
相关推荐
老歌老听老掉牙1 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
周杰偷奶茶1 小时前
【Java】数组的定义和使用(附管理系统实战案例)
java·开发语言
zhangfeng11332 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
橙子圆1232 小时前
JUC之集合类不安全
java·开发语言
学代码的CJY2 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录2 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
谢亮_vipxieliang3 小时前
Stream API 不是银弹:常见坑与性能建议
java·开发语言
小O的算法实验室3 小时前
IEEE TEVC,基于精确与DQN群智能调度方法用于多目标异构USV
算法
源码宝3 小时前
Web‑PACS 云影像源码|Java+Vue3 医院影像管理系统完整方案
java·源码·影像pacs·成品源码·医院影像系统