二维静态差分

二维静态差分

二维差分是一维差分在二维平面上的扩展,用于处理矩阵的子矩阵修改问题。
通过二维差分数组,可以将子矩阵修改的时间复杂度从 优化到

基本概念

二维差分的核心思想是:

  1. 构建二维差分数组 ,其中 表示相邻格子的差值
  2. 子矩阵修改转化为差分数组的四个点的修改
  3. 原矩阵可以通过二维前缀和还原
  4. 适用于频繁进行子矩阵修改的场景

实现方式

二维差分的实现步骤:

  1. 构建二维差分数组
  2. 通过四点修改实现子矩阵增加
  3. 通过二维前缀和还原原矩阵
  4. 处理查询操作

基本实现

class Difference2D {
private:
    vector<vector<int>> diff;
    int m, n;
    
public:
    Difference2D(vector<vector<int>>& matrix) {
        m = matrix.size();
        n = matrix[0].size();
        diff.resize(m + 1, vector<int>(n + 1));
        
        // 构建二维差分数组
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                increment(i, j, i, j, matrix[i][j]);
            }
        }
    }
    
    // 子矩阵[(x1,y1), (x2,y2)]增加val
    void increment(int x1, int y1, int x2, int y2, int val) {
        diff[x1][y1] += val;
        diff[x1][y2 + 1] -= val;
        diff[x2 + 1][y1] -= val;
        diff[x2 + 1][y2 + 1] += val;
    }
    
    // 还原原矩阵
    vector<vector<int>> result() {
        vector<vector<int>> res(m, vector<int>(n));
        // 二维前缀和
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res[i][j] = diff[i][j];
                if (i > 0) res[i][j] += res[i-1][j];
                if (j > 0) res[i][j] += res[i][j-1];
                if (i > 0 && j > 0) res[i][j] -= res[i-1][j-1];
            }
        }
        return res;
    }
};
class Difference2D {
    private int[][] diff;
    private int m, n;
    
    public Difference2D(int[][] matrix) {
        m = matrix.length;
        n = matrix[0].length;
        diff = new int[m + 1][n + 1];
        
        // 构建二维差分数组
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                increment(i, j, i, j, matrix[i][j]);
            }
        }
    }
    
    // 子矩阵[(x1,y1), (x2,y2)]增加val
    public void increment(int x1, int y1, int x2, int y2, int val) {
        diff[x1][y1] += val;
        diff[x1][y2 + 1] -= val;
        diff[x2 + 1][y1] -= val;
        diff[x2 + 1][y2 + 1] += val;
    }
    
    // 还原原矩阵
    public int[][] result() {
        int[][] res = new int[m][n];
        // 二维前缀和
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                res[i][j] = diff[i][j];
                if (i > 0) res[i][j] += res[i-1][j];
                if (j > 0) res[i][j] += res[i][j-1];
                if (i > 0 && j > 0) res[i][j] -= res[i-1][j-1];
            }
        }
        return res;
    }
}
class Difference2D:
    def __init__(self, matrix):
        self.m = len(matrix)
        self.n = len(matrix[0])
        self.diff = [[0] * (self.n + 1) for _ in range(self.m + 1)]
        
        # 构建二维差分数组
        for i in range(self.m):
            for j in range(self.n):
                self.increment(i, j, i, j, matrix[i][j])
    
    # 子矩阵[(x1,y1), (x2,y2)]增加val
    def increment(self, x1, y1, x2, y2, val):
        self.diff[x1][y1] += val
        self.diff[x1][y2 + 1] -= val
        self.diff[x2 + 1][y1] -= val
        self.diff[x2 + 1][y2 + 1] += val
    
    # 还原原矩阵
    def result(self):
        res = [[0] * self.n for _ in range(self.m)]
        # 二维前缀和
        for i in range(self.m):
            for j in range(self.n):
                res[i][j] = self.diff[i][j]
                if i > 0: res[i][j] += res[i-1][j]
                if j > 0: res[i][j] += res[i][j-1]
                if i > 0 and j > 0: res[i][j] -= res[i-1][j-1]
        return res

应用场景

二维差分在很多问题中都有应用:

  1. 图像区域修改
  2. 地图区域更新
  3. 矩阵区域增减
  4. 二维网格修改
  5. 热力图更新

示例:矩阵区域增加

vector<vector<int>> getModifiedMatrix(vector<vector<int>>& matrix, 
                                    vector<vector<int>>& operations) {
    Difference2D diff(matrix);
    
    // 执行所有更新操作
    for (const auto& op : operations) {
        int x1 = op[0], y1 = op[1];
        int x2 = op[2], y2 = op[3];
        int val = op[4];
        diff.increment(x1, y1, x2, y2, val);
    }
    
    return diff.result();
}
public int[][] getModifiedMatrix(int[][] matrix, int[][] operations) {
    Difference2D diff = new Difference2D(matrix);
    
    // 执行所有更新操作
    for (int[] op : operations) {
        int x1 = op[0], y1 = op[1];
        int x2 = op[2], y2 = op[3];
        int val = op[4];
        diff.increment(x1, y1, x2, y2, val);
    }
    
    return diff.result();
}
def getModifiedMatrix(self, matrix: List[List[int]], operations: List[List[int]]) -> List[List[int]]:
    diff = Difference2D(matrix)
    
    # 执行所有更新操作
    for x1, y1, x2, y2, val in operations:
        diff.increment(x1, y1, x2, y2, val)
    
    return diff.result()

时间复杂度

  • 构建差分数组:
  • 子矩阵修改:
  • 单点查询:(需要还原原矩阵)
  • 空间复杂度:

二维差分 vs 一维差分

优点:

  1. 支持二维区域修改
  2. 实现相对简单
  3. 适用于多个区域修改

缺点:

  1. 查询需要还原整个矩阵
  2. 空间复杂度较高
  3. 不支持动态修改

注意事项

  1. 差分数组的大小处理
  2. 子矩阵修改的边界
  3. 还原时的前缀和计算
  4. 处理负数和溢出

练习建议

  1. 实现基本的二维差分
  2. 解决矩阵修改问题
  3. 结合实际应用场景
  4. 尝试动态二维差分

经典例题

  1. 【模板】二维差分
牛客代码笔记-牛栋 文章被收录于专栏

汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。

全部评论

相关推荐

92Y:泡成巨人观了吧
投递百度等公司10个岗位
点赞 评论 收藏
分享
08-08 16:33
唐山学院 Java
职场水母:首先,简历太长,对于实习和应届找工作,hr一眼扫的是学历,技术看实习,你写的技术栈字太多了,尽量用一句话概括不用写那么详细,技术面的时候会问的,而且技术栈都会在实习或者项目里体现,你要做的是,把你的简历浓缩为一页,删除没用的东西,比如实践经历,自我评价,这些纯废话,没用,专业技能写的太离谱,你真的熟练掌握了吗,建议都写熟悉,找工作和写论文不一样,追求的是干练和实用,把实习经历和项目提前,把掌握的技术栈写到最后,然后去找实习,
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务