前缀和(8)_矩阵区域和

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

前缀和(8)_矩阵区域和

收录于专栏【经典算法练习
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

温馨提示:

[1. 题目链接 :](#1. 题目链接 :)

[2. 题目描述 :](#2. 题目描述 :)

[3. 解法(二维前缀和) :](#3. 解法(二维前缀和) :)

题目解释:

[算法思路 :](#算法思路 :)

二位前缀和模板快速记忆:

[1. 求二维前缀和](#1. 求二维前缀和)

[2. 使用二维前缀和](#2. 使用二维前缀和)

细节处理:

[代码展示 :](#代码展示 :)

[结果分析 :](#结果分析 :)


温馨提示:

本题需要使用二维前缀和模板,如果大家还不知道的话,可以查看下篇博客:

前缀和(2)_【模板】二维前缀和_模板-CSDN博客

1. 题目链接 :

OJ链接: 矩阵区域和

2. 题目描述 :

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

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 == mat.length

n == mati.length

1 <= m, n, k <= 100

1 <= matij <= 100

3. 解法(二维前缀和) :

题目解释:

就是目标点向四周延申k个,然后求出在合法区间的总和

算法思路 :

二维前缀和的简单应用题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的左上角以及右下角的坐标(推荐大家画图)

左上角坐标: x1 = i - k, y1 = j - k, 但是由于会超过矩阵的范围,因此需要对0取一个max.因此修正后的坐标为: x2 = min(m - 1, i + k) y2 = min(n - 1, j + k)

然后将求出出来的坐标带入到二位前缀和矩阵的计算公式上即可~(但是要注意下标的映射关系,放到下面分析)

二位前缀和模板快速记忆:

1. 求二维前缀和

首先划出草图,我们这里的思路是:

将当前整个面积分成dpx - 1y + dpxy - 1 + numsxy

因为dpx - 1y - 1多加了一次,我们需要在减去一次dpx - 1y - 1

公式为 : dpxy = dpx - 1y + dpxy - 1 + numsxy - dpx - 1y - 1

2. 使用二维前缀和

首先划出草图,我们这里的思路是:

将当前整个面积分成dpx1 - 1y1 - 1 dpx2y1 - 1 dpx1 - 1y2

公式为 : ret = dpx2y2 - dpx1 - 1y2 - dpx2y1 -1 + dpx1 -1y1 - 1

细节处理:

下标的映射关系:

因为题目原数组从0开始,我们的二维前缀和数组需要访问-1的位置,这样就会导致访问未知内存程序崩溃,所以我们可以将第0行第0列不填数,规避这道题的边界问题.

代码展示 :

cpp 复制代码
class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int n = mat.size(), m = mat[0].size();
        vector<vector<int>> dp(n + 1, vector<int> (m + 1));

        //求前缀和
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + mat[i - 1][j - 1] - dp[i - 1][j - 1];

        //使用前缀和
        vector<vector<int>> ret(n, vector<int> (m));
        for(int i = 0; i < n; i++)
            for(int j = 0; j < m; j++)
            {
                int x1 = max(0, i - k) + 1, y1 = max(0, j - k) + 1;
                int x2 = min(n - 1, i + k) + 1, y2 = min(m - 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;
    }
};

代码分析:

前缀和计算:

使用 dp 数组来存储 mat 的前缀和。dpij 表示从 mat00 到 mati - 1j - 1 的所有元素的和。

前缀和的公式为:
dpij = dpi−1j + dpij−1 + mati−1j−1−dpi−1j−1

这样,dp 数组的每个元素能够快速计算出任意子矩阵的和。
块和计算:

使用前缀和 dp 来计算每个元素的块和:

计算块的边界:

左上角(x1, y1) 为(max(0, i - k) + 1, max(0, j - k) + 1)
右下角(x2, y2) 为(min(n - 1, i + k) + 1, min(m - 1, j + k) + 1)

利用前缀和公式来计算块和:
块和 = dpx2y2−dpx1−1y2−dpx2y1−1 + dpx1−1y1−1
结果存储:

将每个块的和存储在 ret 数组中,并最终返回。

结果分析 :

时间复杂度

前缀和的计算时间复杂度为O(n×m),因为需要遍历整个矩阵一次。

计算每个元素的块和的时间复杂度也是O(n×m),同样是遍历整个矩阵一次。

因此,总的时间复杂度为:O(n×m)
空间复杂度

dp 数组的大小为(n + 1)×(m + 1),因此空间复杂度为O(n×m)。

ret 数组的大小为n×m,也为O(n×m)。

因此,总的空间复杂度也是:O(n×m)

相关推荐
_wyt0014 小时前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
通信小呆呆6 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
Bobolink_6 小时前
TikTok矩阵账号如何批量养号?工作室级运营方案分享
矩阵·内容运营·跨境电商·tik tok·账号运营
benben0446 小时前
强化学习之DQN算法族(基于gymnasium开发)
算法
小小工匠7 小时前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
玖玥拾7 小时前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
何以解忧,唯有..7 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
想吃火锅10058 小时前
【leetcode】88.合并两个有序数组js
算法
один but you8 小时前
constexpr函数
c++