LeetCode 热题 100 : 矩阵

58 阅读4分钟

1. 矩阵置零

题目描述

给定一个 m x n 的整数矩阵,如果某个元素为 0,则将其所在行与列的所有元素都设为 0。要求原地修改

解题思路

💡 核心技巧:利用首行首列作为标记空间(原地标记)
若直接置零会丢失原始信息,需先标记再统一处理。

关键洞察

  • 使用 matrix[0][*] 标记各列是否应置零
  • 使用 matrix[*][0] 标记各行是否应置零
  • 但首行和首列自身也需要被标记 → 额外用两个布尔变量 firstRowZerofirstColZero 记录

代码实现

/**
 * @param {number[][]} matrix
 * @return {void} Do not return anything, modify matrix in-place instead.
 */
var setZeroes = function(matrix) {
    const m = matrix.length;
    const n = matrix[0].length;
    let firstRowZero = false;
    let firstColZero = false;

    // 检查首行是否有0
    for (let j = 0; j < n; j++) {
        if (matrix[0][j] === 0) {
            firstRowZero = true;
            break;
        }
    }
    // 检查首列是否有0
    for (let i = 0; i < m; i++) {
        if (matrix[i][0] === 0) {
            firstColZero = true;
            break;
        }
    }

    // 用首行/首列标记内部区域的0
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            if (matrix[i][j] === 0) {
                matrix[i][0] = 0;
                matrix[0][j] = 0;
            }
        }
    }

    // 根据标记置零内部区域
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            if (matrix[i][0] === 0 || matrix[0][j] === 0) {
                matrix[i][j] = 0;
            }
        }
    }

    // 处理首行和首列
    if (firstRowZero) {
        for (let j = 0; j < n; j++) matrix[0][j] = 0;
    }
    if (firstColZero) {
        for (let i = 0; i < m; i++) matrix[i][0] = 0;
    }
};

复杂度分析

  • 时间复杂度:O(mn)
  • 空间复杂度:O(1)

2. 螺旋矩阵

题目描述

给定一个 m x n 矩阵,按顺时针螺旋顺序返回所有元素。

解题思路

💡 核心技巧:边界收缩法(模拟遍历)
维护四个边界:top, bottom, left, right,每走完一圈就收缩边界。

关键洞察

  • 按「上→右→下→左」顺序遍历
  • 每次遍历完一条边,对应边界向内收缩
  • 注意:在遍历下边和左边前,需检查 top <= bottomleft <= right,防止重复访问

代码实现

/**
 * @param {number[][]} matrix
 * @return {number[]}
 */
var spiralOrder = function(matrix) {
    if (matrix.length === 0 || matrix[0].length === 0) return [];

    let top = 0;
    let bottom = matrix.length - 1;
    let left = 0;
    let right = matrix[0].length - 1;
    const result = [];

    while (top <= bottom && left <= right) {
        // 从左到右遍历上边界
        for (let col = left; col <= right; col++) {
            result.push(matrix[top][col]);
        }
        top++;

        // 从上到下遍历右边界
        for (let row = top; row <= bottom; row++) {
            result.push(matrix[row][right]);
        }
        right--;

        // 从右到左遍历下边界
        if (top <= bottom) {
            for (let col = right; col >= left; col--) {
                result.push(matrix[bottom][col]);
            }
            bottom--;
        }

        // 从下到上遍历左边界
        if (left <= right) {
            for (let row = bottom; row >= top; row--) {
                result.push(matrix[row][left]);
            }
            left++;
        }
    }

    return result;
};

复杂度分析

  • 时间复杂度:O(mn)
  • 空间复杂度:O(1)

3. 旋转图像

题目描述

给定一个 n x n 的二维矩阵,原地顺时针旋转 90 度

解题思路

💡 核心技巧:转置 + 行反转
数学变换:顺时针旋转 90° = 先沿主对角线转置,再水平翻转每行。

关键洞察

  • 转置:matrix[i][j] ↔ matrix[j][i]
  • 行反转:matrix[i].reverse()
  • 两者结合即为旋转

代码实现

/**
 * @param {number[][]} matrix
 * @return {void} Do not return anything, modify matrix in-place instead.
 */
var rotate = function(matrix) {
    const n = matrix.length;

    // Step 1: 转置(沿主对角线翻转)
    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {
            [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
        }
    }

    // Step 2: 每行反转(水平翻转)
    for (let i = 0; i < n; i++) {
        matrix[i].reverse();
    }
};

复杂度分析

  • 时间复杂度:O(n²)
  • 空间复杂度:O(1)

4. 搜索二维矩阵 II

题目描述

给定一个 m x n 矩阵,每行从左到右升序,每列从上到下升序。判断目标值 target 是否存在。

解题思路

💡 核心技巧:从左下角(或右上角)开始的“阶梯搜索”

  1. 起点选在左下角(或右上角)是因为这个位置具有“一个方向增大,一个方向减小”的特性
  2. 每一步都能排除一行或一列,不会遗漏可能包含target的区域
  3. 因此,算法是贪心且完备的

关键洞察

  • 从左下角 (m-1, 0) 出发:
    • matrix[x][y]=target→找到目标值
    • matrix[x][y] < target → 当前行过小,y++
    • matrix[x][y] > target → 当前列过大,x--
  • 类似二叉搜索树的路径

代码实现

/**
 * @param {number[][]} matrix
 * @param {number} target
 * @return {boolean}
 */
var searchMatrix = function (matrix, target) {
    let m = matrix.length
    let n = matrix[0].length
    let x = m - 1
    let y = 0
    while (x >= 0 && y < n) {
        if (matrix[x][y] === target) return true
        else if (matrix[x][y] < target) y++
        else x--
    }
    return false
};

复杂度分析

  • 时间复杂度:O(m + n)
  • 空间复杂度:O(1)

总结对比

题目核心技巧关键优化
矩阵置零原地标记(首行首列作哈希)用两个布尔变量保护首行首列
螺旋矩阵边界收缩模拟遍历下/左边前需检查边界有效性
旋转图像转置 + 行反转数学变换替代复杂坐标计算
搜索二维矩阵 II阶梯搜索利用行列有序性实现线性搜索

希望这篇解析对你有帮助!欢迎继续关注 LeetCode 热题 100 系列 👋