【力扣刷题实战】矩阵区域和

大家好,我是小卡皮巴拉

文章目录

目录

力扣题目:矩阵区域和

题目描述

解题思路

问题理解

算法选择

具体思路

解题要点

完整代码(C++)

[兄弟们共勉 !!!](#兄弟们共勉 !!!)


每篇前言

博客主页:小卡皮巴拉

咱的口号:🌹小比特,大梦想🌹

作者请求:由于博主水平有限,难免会有错误和不准之处,我也非常渴望知道这些错误,恳请大佬们批评斧正。

力扣题目:矩阵区域和

原题链接:1314. 矩阵区域和 - 力扣(LeetCode)

题目描述

给你一个 m x n 的矩阵 mat 和一个整数 k ,请你返回一个矩阵 answer ,其中每个 answer[i][j] 是所有满足下述条件的元素 mat[r][c] 的和:

  • i - k <= r <= i + k,
  • j - k <= c <= j + k
  • (r, c) 在矩阵内。

示例 1:

复制代码
输入:mat = [[1,2,3],[4,5,6],[7,8,9]], k = 1
输出:[[12,21,16],[27,45,33],[24,39,28]]

示例 2:

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

解题思路

问题理解

本题要求对于给定的 m x n 矩阵 mat 和整数 k,计算一个新的矩阵 answer,其中 answer[i][j] 是满足 i - k <= r <= i + kj - k <= c <= j + k 的所有 mat[r][c] 元素的和,同时要保证 (r, c) 在矩阵内。

算法选择

采用二维前缀和的算法。通过预处理一个前缀和矩阵,可以在 O(1) 的时间复杂度内计算出任意子矩阵的和,从而将整体的时间复杂度降低到 O(mn)。

具体思路

  1. 预处理前缀和矩阵

    • 创建一个大小为 (m + 1) x (n + 1) 的二维数组 dp 作为前缀和矩阵,多一行一列是为了方便处理边界情况。

    • 使用双重循环遍历矩阵 mat,对于每个位置 (i, j),计算 dp[i][j] 的值,其计算公式为 dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mat[i - 1][j - 1]。这里减去 dp[i - 1][j - 1] 是为了避免重复计算左上角的元素。

  2. 计算结果矩阵

    • 创建一个大小为 m x n 的二维数组 ret 作为结果矩阵。

    • 再次使用双重循环遍历矩阵 mat 的每个元素 (i, j)

    • 对于每个元素 (i, j),计算其对应的子矩阵的左上角坐标 (x1, y1) 和右下角坐标 (x2, y2),使用 maxmin 函数确保坐标不越界。

    • 利用前缀和矩阵 dp 计算子矩阵的和,公式为 ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]

  3. 返回结果

    • 遍历完矩阵 mat 后,ret 矩阵中存储的就是最终结果,返回 ret

解题要点

  1. 前缀和矩阵的计算:正确理解和使用二维前缀和的状态转移方程,避免重复计算元素。

  2. 边界处理 :在计算子矩阵的左上角和右下角坐标时,使用 maxmin 函数确保坐标不越界。

  3. 子矩阵和的计算:利用前缀和矩阵的性质,通过四个前缀和的加减运算在 O(1) 的时间复杂度内计算出子矩阵的和。

完整代码(C++)

cpp 复制代码
class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) 
    {
        // 获取矩阵 mat 的行数 m 和列数 n
        int m = mat.size(), n = mat[0].size(); 
        // 1. 预处理一个前缀和矩阵
        // dp 矩阵用于存储前缀和,大小为 (m + 1) x (n + 1),多一行一列是为了方便处理边界情况
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        // 双重循环遍历矩阵,计算前缀和
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
                // 状态转移方程:当前位置的前缀和等于上方位置的前缀和加上左方位置的前缀和
                // 减去左上方位置的前缀和(避免重复计算),再加上当前矩阵元素的值
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mat[i - 1][j - 1];

        // 2. 使用前缀和矩阵计算结果矩阵
        // ret 矩阵用于存储最终结果,大小为 m x n
        vector<vector<int>> ret(m, vector<int>(n));
        // 双重循环遍历矩阵 mat 的每个元素
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                // 计算当前元素 (i, j) 对应的子矩阵的左上角坐标 (x1, y1)
                // 使用 max 函数确保坐标不越界,加 1 是因为 dp 矩阵多了一行一列
                int x1 = max(0, i - k) + 1, y1 = max(0, j - k) + 1;
                // 计算当前元素 (i, j) 对应的子矩阵的右下角坐标 (x2, y2)
                // 使用 min 函数确保坐标不越界,加 1 是因为 dp 矩阵多了一行一列
                int x2 = min(m - 1, i + k) + 1, y2 = min(n - 1, j + k) + 1;
                // 利用前缀和矩阵计算子矩阵的和
                // 公式为:右下角前缀和 - 左上角上方前缀和 - 左上角左方前缀和 + 左上角左上方前缀和
                ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];
            }
        }
        // 返回结果矩阵
        return ret;
    }
};

兄弟们共勉 !!!

码字不易,求个三连

抱拳了兄弟们!

相关推荐
郝学胜-神的一滴1 分钟前
谨慎地迭代函数所收到的参数 (Effective Python 第31条)
开发语言·python·程序人生·软件工程
MobotStone2 分钟前
LLM 采样入门到进阶:理解与实践 Top-K、Top-P、温度控制
算法
ShineSpark14 分钟前
C++面试11——指针与引用
c++·面试
杨小码不BUG34 分钟前
CSP-J/S初赛知识点精讲-图论
c++·算法·图论··编码·csp-j/s初赛
大虾别跑41 分钟前
vc无法启动
java·开发语言
郭老二1 小时前
【JAVA】从入门到放弃-01-HelloWorld
java·开发语言
初圣魔门首席弟子1 小时前
flag使用错误出现bug
c++·bug
北城以北88881 小时前
JavaScript--基础ES(一)
开发语言·javascript·intellij-idea
say_fall1 小时前
C语言底层学习(2.指针与数组的关系与应用)(超详细)
c语言·开发语言·学习
eqwaak01 小时前
Python Pillow库详解:图像处理的瑞士军刀
开发语言·图像处理·python·语言模型·pillow