308 二维区域和检索 - 可变

题目描述:
给你一个 2D 矩阵 matrix,请计算出从左上角 (row1, col1) 到右下角 (row2, col2) 组成的矩形中所有元素的和。
在这里插入图片描述
上述粉色矩形框内的,该矩形由左上角 (row1, col1) = (2, 1) 和右下角 (row2, col2) = (4, 3) 确定。其中,所包括的元素总和 sum = 8。

示例:
给定 matrix = [
[3, 0, 1, 4, 2],
[5, 6, 3, 2, 1],
[1, 2, 0, 1, 5],
[4, 1, 0, 1, 7],
[1, 0, 3, 0, 5]
]
sumRegion(2, 1, 4, 3) -> 8
update(3, 2, 2)
sumRegion(2, 1, 4, 3) -> 10

注意:
矩阵 matrix 的值只能通过 update 函数来进行修改
你可以默认 update 函数和 sumRegion 函数的调用次数是均匀分布的
你可以默认 row1 ≤ row2,col1 ≤ col2

方法1:
主要思路:
(1)和题目304 二维区域和检索 - 矩阵不可变类似,只不过增加了更新原数组元素值的操作;
(2)同样使用积分图像的思路,只不过添加了保存原始数组元素的数组,已实现对元素的更新操作;

class NumMatrix {
public:
    vector<vector<int>> num_matrix;
    vector<vector<int>> sum_matrix;
    NumMatrix(vector<vector<int>>& matrix) {
        if(matrix.empty()||matrix[0].empty()){//处理特殊的情形
            return;
        }
        int rows=matrix.size();
        int cols=matrix[0].size();
        num_matrix=matrix;//保存数组的元素
        sum_matrix=vector<vector<int>>(rows+1,vector<int>(cols+1,0));//积分图像,既保存原数组每个元素左上角所有元素的和
        for(int i=1;i<=rows;++i){
            for(int j=1;j<=cols;++j){
                sum_matrix[i][j]=sum_matrix[i-1][j]+sum_matrix[i][j-1]-sum_matrix[i-1][j-1]+matrix[i-1][j-1];//积分图像数组中每个元素表示原数组中对应位置左上角所有元素之和
            }
        }
    }
    
    void update(int row, int col, int val) {//更新数组元素
        if(num_matrix.empty()){//处理特殊的情形
            return;
        }
        int diff=val-num_matrix[row][col];//计算出当前元素原始值和要更新的值的差异
        num_matrix[row][col]=val;//更新元素值
        //更新积分图像中受影响的各个元素的值
        for(int i=row+1;i<sum_matrix.size();++i){
            for(int j=col+1;j<sum_matrix[0].size();++j){
                sum_matrix[i][j]+=diff;
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        if(num_matrix.empty()){//处理特殊的情形
            return 0;
        }
        //直接返回给出的范围内的元素和
        return sum_matrix[row2+1][col2+1]-sum_matrix[row2+1][col1]-sum_matrix[row1][col2+1]+sum_matrix[row1][col1];
    }
};

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix* obj = new NumMatrix(matrix);
 * obj->update(row,col,val);
 * int param_2 = obj->sumRegion(row1,col1,row2,col2);
 */
### 关于二维前缀的示例题目及其解法 #### 示例题目:LeetCode 304. 二维区域检索 - 矩阵不可变 此题要求实现一个数据结构 `NumMatrix`,用于快速计算给定矩形区域内元素的总。该类应支持初始化时传入整数矩阵 `matrix` 并提供方法 `sumRegion(row1, col1, row2, col2)` 来返回左上角位于 `(row1,col1)` 右下角位于 `(row2,col2)` 的子矩阵内的所有元素之。 为了高效解决这个问题,可以预先计算并保存每个位置到原点(0,0)之间所有元素构成的矩形区域内的累积作为辅助工具,在后续调用过程中利用这些已知的结果加速运算过程[^1]。 ```python class NumMatrix: def __init__(self, matrix: List[List[int]]): if not matrix or not matrix[0]: self.sums = None return m, n = len(matrix), len(matrix[0]) self.sums = [[0]*(n+1) for _ in range(m+1)] for i in range(1,m+1): for j in range(1,n+1): self.sums[i][j]=self.sums[i-1][j]+self.sums[i][j-1]-self.sums[i-1][j-1]+matrix[i-1][j-1] def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int: if self.sums is None: return 0 A=self.sums[row2+1][col2+1] B=self.sums[row1][col2+1] C=self.sums[row2+1][col1] D=self.sums[row1][col1] return A-B-C+D # Your NumMatrix object will be instantiated and called as such: # obj = NumMatrix(matrix) # param_1 = obj.sumRegion(row1,col1,row2,col2) ``` 上述代码实现了基于二维前缀的数据结构,通过提前构建好累加表使得每次查询操作可以在常量时间内完成。具体来说就是先遍历整个输入矩阵一次建立一个新的二维数组用来记录从坐标 (0,0) 到当前坐标的矩形范围内所有数值相加之;之后每当需要获取任意指定范围内的值的时候只需要做简单的四则运算即可得出结果[^4]。 #### 示例题目:LeetCode 661. 图片平滑器 本题旨在对图像中的每一个像素进行处理得到新的颜色强度值,新值等于它自己以及周围八个方向上的邻居们的平均灰度值(如果某个方向不存在有效邻接点,则忽略)。这里同样可以通过构造二维前缀的方式来简化边界情况下的判断逻辑,并提高整体性能表现。 ```cpp vector<vector<int>> imageSmoother(vector<vector<int>>& M) { vector<vector<int>> res(M.size(), vector<int>(M[0].size())); // 构建二维前缀 vector<vector<int>> prefixSum(M.size() + 1, vector<int>(M[0].size() + 1)); for(int i=1; i<=M.size(); ++i){ for(int j=1; j<=M[0].size(); ++j){ prefixSum[i][j] = M[i-1][j-1] + prefixSum[i-1][j] + prefixSum[i][j-1] - prefixSum[i-1][j-1]; } } auto getSum = [&](int r1,int c1,int r2,int c2)->int{ return prefixSum[r2+1][c2+1] - prefixSum[r1][c2+1] - prefixSum[r2+1][c1] + prefixSum[r1][c1]; }; for(size_t i=0;i<M.size();++i){ for(size_t j=0;j<M[0].size();++j){ int cnt = 0; int sr = max((int)i-1,0); int sc = max((int)j-1,0); int er = min(i+1,(int)(M.size()-1)); int ec = min(j+1,(int)(M[0].size()-1)); res[i][j]=(getSum(sr,sc,er,ec)/(pow(er-sr+1,2))); } } return res; } ``` 这段 C++ 实现展示了如何应用二维前缀技术来优化图片平滑化的过程。首先创建了一个额外的空间存储原始图象经过转换后的前缀形式;接着定义了帮助函数 `getSum()` 方便提取特定区间内部的所有元素合计;最后按照规则更新目标输出矩阵中对应位置的新亮度值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值