leetcode 1314

思路一:暴力解法

1.二重循环,对于每个位置都计算r-k,c-k,r+k,c+k,将其与边界比较,确定要求和的区域,区域左上角起始的位置记为(x1,y1),右下角位置(x2,y2),然后根据边界,进入新的二重循环,此时便可累计求和得到ans[r][c]

代码:

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        vector<vector<int>> answer(mat);
        int height=mat.size();
        int length=mat[0].size();
        for(int i=0;i<height;i++)
        {
            for(int j=0;j<length;j++)
            {
                int y1=i-k>0?i-k:0;
                int x1=j-k>0?j-k:0;
                int y2=i+k<(height-1)?i+k:(height-1);
                int x2=j+k<(length-1)?j+k:(length-1);
                answer[i][j]=0;
                for(int ii=y1;ii<=y2;ii++)
                {
                    for(int jj=x1;jj<=x2;jj++)
                        answer[i][j]+=mat[ii][jj];
                }
            }
        }
        return answer;
    }
};

思路二:DP+前缀和

1.通过分析,如果暴力解法,最大时间复杂度为O(m²n²),分析发现,计算每个ans[r][c]时累加过程中可能会重复计算之前已经计算的部分和,因此我们想办法将已经结算的某部分保存下来,留着后续其他元素累加求和时直接使用。
2.在这里我们采用DP的思想,遍历二维数组过程中,对每个位置元素充分利用之前的计算结果,也就是充分利用子问题的求解结果在更短时间内构造出较大子问题的结果,依次迭代计算最终得到原问题的解。
3.首先引入前缀和pre[i][j],代表坐标为i,j,元素的左上角矩形区域元素的和。问题求解过程中可能会需要对整个矩阵进行求和,所以我们将pre矩阵进行扩展,pre的长度变为m+1,高度n+1。同时pre[i][j]的计算也可以采取DP的方式,分析可知,pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+mat[i-1][j-1];
4.然后对原来问题进行分析,对于每一个ans[i][j]而言,不考虑边界超出的问题,我们需要求解的实际上是以mat[i][j]为中心,k为边长的方阵的元素和
实际上,ans[i][j]=pre[i+k+1][j+k+1]-(pre[i+k+1][j]+pre[i][j+k+1])+pre[i-k][j-k]
5.考虑边界超出的情况,如果r-k<0,实际上也就是证明r-k左上角是没有元素的,与其左边框相应位置等价,即[r-k<0][y]的位置和[r-k][y]的位置是等价的,这时我们可以将左上角边界移动到左边框相应位置上;j-k<0,同样道理,将其移动到上边框相应位置上;对于r+k+1>m+1的情况,和上面类似分析,将其移动到右边框的相应位置上即可,j+k+1>n+1的情况同理。

代码:

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        vector<vector<int>> answer(mat);
        int height=mat.size();
        int length=mat[0].size();
        vector<vector<int>> pre(height + 1, vector<int>(length + 1));
        for(int j=0;j<=length;j++)
        {
            pre[j][0]=0;
        }
        for(int i=1;i<=height;i++)
        {
            pre[i][0]=0;
            for(int j=1;j<=length;j++)
            {
                pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+mat[i-1][j-1];
            }
        }
        for(int i=0;i<height;i++)
        {
            for(int j=0;j<length;j++)
            {
                int y1=i-k>0?i-k:0;
                int x1=j-k>0?j-k:0;
                int y2=i+k+1<(height)?i+k+1:(height);
                int x2=j+k+1<(length)?j+1+k:(length);
                answer[i][j]=pre[y2][x2]-(pre[y1][x2]+pre[y2][x1])+pre[y1][x1];
            }
        }
        return answer;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值