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

大家好,我是小卡皮巴拉

文章目录

目录

力扣题目:矩阵区域和

题目描述

解题思路

问题理解

算法选择

具体思路

解题要点

完整代码(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;
    }
};

兄弟们共勉 !!!

码字不易,求个三连

抱拳了兄弟们!

相关推荐
我命由我123451 小时前
Spring Boot 自定义日志打印(日志级别、logback-spring.xml 文件、自定义日志打印解读)
java·开发语言·jvm·spring boot·spring·java-ee·logback
徐小黑ACG2 小时前
GO语言 使用protobuf
开发语言·后端·golang·protobuf
0白露3 小时前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.4 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐4 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
想跑步的小弱鸡4 小时前
Leetcode hot 100(day 3)
算法·leetcode·职场和发展
Tttian6226 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
xyliiiiiL6 小时前
ZGC初步了解
java·jvm·算法
爱的叹息6 小时前
RedisTemplate 的 6 个可配置序列化器属性对比
算法·哈希算法
Merokes6 小时前
关于Gstreamer+MPP硬件加速推流问题:视频输入video0被占用
c++·音视频·rk3588