LeetCode 每日一题笔记 日期:2025.03.21 题目:3643.垂直翻转子矩阵

LeetCode 每日一题笔记

0. 前言

  • 日期:2025.03.21
  • 题目:3643.垂直翻转子矩阵
  • 难度:简单
  • 标签:数组 双指针 矩阵 原地修改

1. 题目理解

问题描述

给你一个 m x n 的整数矩阵 grid,以及三个整数 x、y 和 k。整数 x 和 y 表示一个正方形子矩阵的左上角下标,整数 k 表示该正方形子矩阵的边长。你的任务是垂直翻转子矩阵的行顺序(即上下翻转该正方形子矩阵),返回更新后的矩阵。

示例

输入: grid = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]], x = 1, y = 0, k = 3

输出: [[1,2,3,4],[13,14,15,8],[9,10,11,12],[5,6,7,16]]

解释:

目标正方形子矩阵的左上角为 (1,0),边长 3,覆盖行 1-3、列 0-2:

翻转前子矩阵行内容:[5,6,7]、[9,10,11]、[13,14,15]

垂直翻转后行顺序变为:[13,14,15]、[9,10,11]、[5,6,7]

列 3 不在子矩阵范围内,保持原数值,最终得到输出矩阵。

2. 解题思路

核心观察

  • 垂直翻转正方形子矩阵的本质是上下交换子矩阵的行:第1行与最后1行交换、第2行与倒数第2行交换,直到中间行;
  • 子矩阵的行范围是 [x, x+k-1],列范围是 [y, y+k-1]
  • 可通过双指针法实现原地翻转,无需额外空间:用 top 指向子矩阵顶部行,bottom 指向子矩阵底部行,交换两行对应列的元素后,top 右移、bottom 左移,直到 top ≥ bottom。

算法步骤

  1. 确定子矩阵的行边界:top = x(子矩阵顶部行),bottom = x + k - 1(子矩阵底部行);
  2. 双指针交换行元素
    • 当 top < bottom 时,遍历子矩阵的列范围 [y, y+k-1]
    • 交换 grid[top][i] 和 grid[bottom][i] 的值;
  3. 更新指针:top 加 1,bottom 减 1,重复步骤 2 直到指针相遇;
  4. 返回结果:原地修改矩阵后直接返回。

3. 代码实现

java 复制代码
package com.sheeta1998.lec.lc3643;

public class Solution {
    public int[][] reverseSubmatrix(int[][] grid, int x, int y, int k) {
        int top = x;
        int bottom = x + k - 1;

        while (top < bottom) {
            for (int i = y; i < y + k; i++) {
                int temp = grid[top][i];
                grid[top][i] = grid[bottom][i];
                grid[bottom][i] = temp;
            }
            top++;
            bottom--;
        }
        return grid;
    }
}

4. 代码优化说明

优化点1:参数合法性校验(增强鲁棒性)

实际场景中可添加参数校验,避免越界异常(题目保证输入合法,可选):

java 复制代码
public int[][] reverseSubmatrix(int[][] grid, int x, int y, int k) {
    // 校验参数合法性
    if (grid == null || grid.length == 0 || grid[0].length == 0) return grid;
    int m = grid.length, n = grid[0].length;
    if (x + k > m || y + k > n || k <= 0) return grid;
    
    int top = x;
    int bottom = x + k - 1;
    while (top < bottom) {
        for (int i = y; i < y + k; i++) {
            int temp = grid[top][i];
            grid[top][i] = grid[bottom][i];
            grid[bottom][i] = temp;
        }
        top++;
        bottom--;
    }
    return grid;
}

优化点2:提取交换逻辑为独立方法(代码复用)

若需多次交换行元素,可将交换逻辑封装为方法:

java 复制代码
private void swapRows(int[][] grid, int row1, int row2, int colStart, int colEnd) {
    for (int i = colStart; i < colEnd; i++) {
        int temp = grid[row1][i];
        grid[row1][i] = grid[row2][i];
        grid[row2][i] = temp;
    }
}

public int[][] reverseSubmatrix(int[][] grid, int x, int y, int k) {
    int top = x;
    int bottom = x + k - 1;
    while (top < bottom) {
        swapRows(grid, top, bottom, y, y + k);
        top++;
        bottom--;
    }
    return grid;
}

5. 复杂度分析

  • 时间复杂度:(O(k^2))

    • 双指针遍历的行数为 (k/2)(top 从 x 到 x+k/2);
    • 每行需要交换 k 个列元素;
    • 总操作次数为 (k/2 \times k = O(k^2)),与原矩阵整体大小无关。
  • 空间复杂度:(O(1))

    • 仅使用 temp、top、bottom 等常量级临时变量;
    • 所有操作均为原地修改矩阵,无额外数组/集合开销。

6. 总结

  • 核心思路是双指针原地交换:利用 top/bottom 指针交换子矩阵的上下行,实现垂直翻转,无需额外空间;
  • 关键技巧:明确子矩阵的行/列边界(xx+k-1、yy+k-1),仅处理该范围内的元素;
  • 该方法时间和空间复杂度均最优,适合处理任意大小的合法输入矩阵。

关键点回顾

  1. 垂直翻转子矩阵的核心是行交换,双指针法是实现原地翻转的最优方式;
  2. 时间复杂度仅与子矩阵大小 (k^2) 相关,与原矩阵整体规模无关;
  3. 可通过参数校验增强代码鲁棒性,通过封装方法提升代码复用性。
相关推荐
测试_AI_一辰7 小时前
AI测试工程笔记 05:AI评测实践(从数据集到自动评测闭环)
人工智能·笔记·功能测试·自动化·ai编程
We་ct8 小时前
LeetCode 918. 环形子数组的最大和:两种解法详解
前端·数据结构·算法·leetcode·typescript·动态规划·取反
今儿敲了吗10 小时前
python基础学习笔记第六章——函数进阶
笔记·python·学习
x_xbx10 小时前
LeetCode:83. 删除排序链表中的重复元素
算法·leetcode·链表
左左右右左右摇晃11 小时前
JVM 笔记--分代工程以及分代的算法
jvm·笔记
-Springer-11 小时前
STM32 学习 —— 个人学习笔记9-3(FlyMcu 串口下载)
笔记·stm32·学习
中屹指纹浏览器13 小时前
2026指纹浏览器与代理IP协同安全体系构建——从特征匹配到行为风控的全链路防护
经验分享·笔记
لا معنى له13 小时前
什么是Active Inference(主动推理)? ——学习笔记
笔记·学习
xsyaaaan13 小时前
leetcode-hot100-链表
leetcode·链表