2021-12-09 leetcode 动态规划 1314.矩形区域和 c++

题目

leetcode 1314.矩形区域和
请添加图片描述
解释

已知: 矩阵mat,整数k
求解:对于矩阵mat中的一坐标为(i,j)的元素,在矩阵范围内,求从元素(i - k, j - k)到元素(i + k, j + k)的矩形区域内所有值的和。
example: 如下图所示,对于mat[5][5],k = 1,对于元素(i, j),求(i - 1, j - 1)到(i + 1, j + 1)的矩形区域中所有元素和,即下图黑框框住的矩形中所有元素的和。
请添加图片描述

BF算法

暴力算法思路
遍历mat中所有元素,假设遍历到(i, j),则将限制在mat矩阵范围内的(i - k, j - k)-(i + k, j + k)范围的矩形区域找出,遍历该矩形区域中的元素值并累加得解。

对于矩形区域重点解释
满足两个条件:
1:不超过mat矩阵范围;因此矩形范围区间: 0 <= row < mat.size(); 0 <= col < mat[0].size();
2:(i - k, j - k)-(i + k, j + k)的矩形区域,即矩形内左上角元素坐标为(i - k, j - k),右下角元素坐标为(i + k, j + k)。则矩形范围区间:i-k <= row <= i+k; j-k <= col <= j+k;
因此,矩形区间的行和列具体范围取决于:左区间的更大的一方,右区间更小的一方

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size(), n = mat[0].size();
        vector<vector<int>> matrix(m, vector(n, 0));
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                int sum = 0;
                for(int x = max(i - k, 0); x < min(i + k, m - 1); x++) {
                    for(int y = max(j - k, 0); y < min(j + k, n - 1); j++) 
                        sum += mat[x][y];
                }
                matrix[i][j] = sum;
            }
        }
        return matrix;
    }
};

动态规划

求状态转移方程

s[I][j]

vector<vector> s(m + 1, vector(n + 1, 0)) (m,n分别为mat的长和宽)
构造更大的范围是更利于计算s,因此mat中的元素在s中需要扩大。
s[I][j]:表示的是以mat[i - 1][j - 1]为右下角的矩形区域的所有值的和
以(i, j)为右下角的矩形区域所有值的和。如图所示
请添加图片描述
对于mat[I][j],求s[I+1][j+1]
如下图所示
s[I+1][j+1] = 红色矩形区域值 + 绿色矩形区域值 - 黑色虚线框矩形区域值 + mat[i][j]
请添加图片描述

res[I][j]

res[I][j]:表示矩形区域内所有值的和
res[I][j] = 黑色虚线框部分 - 红色部分 - 绿色部分 + 白色部分
请添加图片描述

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size(), n = mat[0].size();
        vector<vector<int>> s(m + 1, vector(n + 1, 0));
        vector<vector<int>> res(m, vector(n, 0));
        //求矩形前缀和,s[i + 1][j + 1]表示的是mat[i][j]的矩形前缀和
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) 
                s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + mat[i - 1][j - 1];
        }
        //求res
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                int xMin = max(0, i - k), yMin = max(0, j - k);
                int xMax = min(m - 1, i + k), yMax = min(n - 1, j + k);
                res[i][j] = s[xMax + 1][yMax + 1] - s[xMin][yMax + 1] - s[xMax + 1][yMin] + s[xMin][yMin];
            }
        }
    return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聪明的Levi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值