前缀和——矩阵区域和

一.题目描述

1314. 矩阵区域和 - 力扣(LeetCode)

二.题目解析

题目乍一看就是求个矩阵,仔细一看这矩阵砸球啊?题目叽里咕噜说什么呢?下面用图来展示一下,题目的要求:

answer[i][j]位置的元素就是以mat对应位置为中心,然后k为半径的矩阵的和。

题目所求的矩阵, 本质就是需要求一段矩阵的和,所以快速求矩阵的和我们就可以使用二维前缀和来解决问题。

三.算法原理

二维前缀和

1.预处理二维前缀和数组

我们首先回顾一下二维前缀和数组每个位置表示的是什么:dp[i][j]表示的是原数组从(1,1)~(i,j)这个矩阵的和。

2.使用前缀和数组

我们使用二维前缀和数组就可以求出原数组中某一段区间的和

接下里我们要将其融入到我们的answer中,answer求得也是一个区间的和,但是我们只知道中心下标,为了求这个区间的和,我们得知道这个区间的左上和右下的下标,依次来使用前缀和数组:

但是需要注意的是,我们求这连个点的下标时,有可能会导致越界。就如示例一种answer的(0,0)位置的值,它的左上下标已经越界了,所以我们要对其进行处理。

如果左上的下标为负数了,其应该变为0;如果右下的下标大于n-1/m-1,就应该变为n-1/m-1。

这里有一个简单的方法来修正下标:

x1 = max(0,i-k),y1 = max(0,j-k);x2 = min(n-1,i+k),y2 = min(m-1,j+k)

最后将该作坐标带入上面的公式即可。

3.细节处理

我们这里的mat数组是从0,0位置开始的。而我们在预处理dp数组时,为了避免边界情况(计算后的下标小于0),下标是从1,1开始的。所以我们在预处理时加最后的d时,其实对应的是mat数组的mat[i-1][j-1]

还有就是使用dp数组时,answer返回数组的下标是从0,0开始的,而dp数组从1,1开始才是有效数据。我们计算下标是按照answer来计算的,而我们下标最后应用的数组却是dp数组。所以要给计算来的下标加上1.

x1 = max(0,i-k) + 1,y1 = max(0,j-k)+ 1;x2 = min(n-1,i+k)+ 1,y2 = min(m-1,j+k)+ 1.

时间复杂度:预处理二维数组时需要遍历一遍矩阵,后面使用二维数组都是常数级的时间复杂度,所以时间复杂度为O(MN)

空间复杂度:我们额外开了一个(m+1)*(n+1)大的空间来存储前缀和数组,所以空间复杂度为O(MN)

四.代码实现

复制代码
// C++

class Solution 
{
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) 
    {
        int m = mat.size();
        int n = mat[0].size();
        vector<vector<int>> answer(m,vector<int>(n));

        // 初始化dp数组
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        for(int i=1; i<m+1; ++i)
            for(int j=1; j<n+1; ++j)
                dp[i][j] = dp[i][j-1] + dp[i-1][j] - dp[i-1][j-1] + mat[i-1][j-1];

        // 使用dp数组
        for(int i=0; i<m; ++i)
            for(int j=0; j<n; ++j)
            {
                int x1 = max(0,i-k) + 1, y1 = max(0,j-k) + 1;
                int x2 = min(m-1,i+k) + 1, y2 = min(n-1,j+k) + 1;

                answer[i][j] = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1];
            }
        return answer;
    }
};

# python

class Solution:
    def matrixBlockSum(self, mat: List[List[int]], k: int) -> List[List[int]]:
        m,n = len(mat),len(mat[0])
        answer = [[0]*n for _ in range(m)]

        # 预处理二维前缀和数组
        dp = [[0]*(n+1)for _ in range(m+1)]
        for i in range(1,m+1):
            for j in range(1,n+1):
                dp[i][j] = dp[i][j-1] + dp[i-1][j]+mat[i-1][j-1]-dp[i-1][j-1]
        
        # 使用前缀和数组
        for i in range(0,m):
            for j in range(0,n):
                x1,y1 = max(0,i-k) + 1,max(0,j-k) + 1
                x2,y2 = min(m-1,i+k) + 1,min(n-1,j+k) + 1
                answer[i][j] = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1]
        return answer
相关推荐
WWZZ20257 分钟前
快速上手大模型:机器学习3(多元线性回归及梯度、向量化、正规方程)
人工智能·算法·机器学习·机器人·slam·具身感知
东方佑1 小时前
从字符串中提取重复子串的Python算法解析
windows·python·算法
西阳未落2 小时前
LeetCode——二分(进阶)
算法·leetcode·职场和发展
通信小呆呆2 小时前
以矩阵视角统一理解:外积、Kronecker 积与 Khatri–Rao 积(含MATLAB可视化)
线性代数·算法·matlab·矩阵·信号处理
CoderCodingNo3 小时前
【GESP】C++四级真题 luogu-B4068 [GESP202412 四级] Recamán
开发语言·c++·算法
一个不知名程序员www3 小时前
算法学习入门---双指针(C++)
c++·算法
Shilong Wang4 小时前
MLE, MAP, Full Bayes
人工智能·算法·机器学习
Theodore_10224 小时前
机器学习(6)特征工程与多项式回归
深度学习·算法·机器学习·数据分析·多项式回归
知花实央l4 小时前
【算法与数据结构】拓扑排序实战(栈+邻接表+环判断,附可运行代码)
数据结构·算法
lingling0094 小时前
机械臂动作捕捉系统选型指南:从需求到方案,NOKOV 度量光学动捕成优选
人工智能·算法