LeetCode 2536.子矩阵元素加 1:二维差分数组

【LetMeFly】2536.子矩阵元素加 1:二维差分数组

力扣题目链接:https://leetcode.cn/problems/increment-submatrices-by-one/

给你一个正整数 n ,表示最初有一个 n x n 、下标从 0 开始的整数矩阵 mat ,矩阵中填满了 0 。

另给你一个二维整数数组 query 。针对每个查询 query[i] = [row1i, col1i, row2i, col2i] ,请你执行下述操作:

  • 找出 左上角(row1i, col1i)右下角(row2i, col2i) 的子矩阵,将子矩阵中的 每个元素1 。也就是给所有满足 row1i <= x <= row2icol1i <= y <= col2imat[x][y]1

返回执行完所有操作后得到的矩阵 mat

示例 1:

复制代码
输入:n = 3, queries = [[1,1,2,2],[0,0,1,1]]
输出:[[1,1,0],[1,2,1],[0,1,1]]
解释:上图所展示的分别是:初始矩阵、执行完第一个操作后的矩阵、执行完第二个操作后的矩阵。
- 第一个操作:将左上角为 (1, 1) 且右下角为 (2, 2) 的子矩阵中的每个元素加 1 。 
- 第二个操作:将左上角为 (0, 0) 且右下角为 (1, 1) 的子矩阵中的每个元素加 1 。 

示例 2:

复制代码
输入:n = 2, queries = [[0,0,1,1]]
输出:[[1,1],[1,1]]
解释:上图所展示的分别是:初始矩阵、执行完第一个操作后的矩阵。 
- 第一个操作:将矩阵中的每个元素加 1 。

提示:

  • 1 <= n <= 500
  • 1 <= queries.length <= 104
  • 0 <= row1i <= row2i < n
  • 0 <= col1i <= col2i < n

Long time no see.

解题方法:二维差分数组

使用二维差分数组diff,其中令diff[i][j]表示原数组mat[i][j]mat[n-1][n-1]每个元素变化值。

例如将mat[x1][y1]mat[x2][y2]每个元素值加一,反映到差分数组上就表现为:

  1. d i f f [ x 1 ] [ y 1 ] + = 1 diff[x1][y1] += 1 diff[x1][y1]+=1,先从mat[x1][y1]mat[n-1][n-1]每个元素都加一
  2. d i f f [ x 2 + 1 ] [ y 1 ] − = 1 diff[x2+1][y1] -= 1 diff[x2+1][y1]−=1,由于从mat[x2+1][y1]mat[n-1][n-1]每个元素无需改变,第一步加的范围太大了,不该变的撤销变化
  3. d i f f [ x 1 ] [ y 2 + 1 ] − = 1 diff[x1][y2+1] -= 1 diff[x1][y2+1]−=1,与2同理,由于从mat[x1][y2+1]mat[n-1][n-1]每个元素无需改变,第一步加的范围太大了,不该变的撤销变化
  4. d i f f [ x 2 + 1 ] [ y 2 + 1 ] + = 1 diff[x2+1][y2+1] += 1 diff[x2+1][y2+1]+=1,由于第二步和第三步都包含范围mat[x2+1][y2+1],所以这块"重复撤销"了,再加回来

对于每个query,以 O ( 1 ) O(1) O(1)的时间复杂度可以计算出diff数组的变化。最终处理完所有query,再由diff差分数组反推出原数组mat就好了。

二维数组思考困难的话可以以一位数组为例,一位差分数组的前缀和数组就是原始数组,二维数组也是如此。只需要对diff数组求前缀和,就能得到原始mat数组了。

前缀和prefix[i][j]代表从diff[0][0]diff[i][j]的所有元素之和。求前缀和的过程可以由左上到右下的顺序求得。

和求差分数组过程类似, p r e f i x [ i ] [ j ] = d i f f [ i ] [ j ] + p r e f i x [ i − 1 ] [ j ] + p r e f i x [ i ] [ j − 1 ] − p r e f i x [ i − 1 ] [ j − 1 ] prefix[i][j] = diff[i][j] + prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1] prefix[i][j]=diff[i][j]+prefix[i−1][j]+prefix[i][j−1]−prefix[i−1][j−1]。

解释为:从diff[0][0]diff[i][j]的所有元素之和 = = = 从diff[0][0]diff[i-1][j]的所有元素之和 + + + 从diff[0][0]diff[i][j-]的所有元素之和 − - − 从diff[0][0]diff[i-1][j-1]的所有元素之和(算重了)。

  • 时间复杂度 O ( n 2 + l e n ( q u e r i e s ) ) O(n^2+len(queries)) O(n2+len(queries))
  • 空间复杂度 O ( n 2 ) O(n^2) O(n2)

AC代码

C++
cpp 复制代码
/*
 * @LastEditTime: 2025-11-14 18:07:20
 */
class Solution {
public:
    vector<vector<int>> rangeAddQueries(int n, vector<vector<int>>& queries) {
        vector<vector<int>> diff(n + 1, vector<int>(n + 1));
        for (vector<int>& q : queries) {
            int x1 = q[0], y1 = q[1], x2 = q[2], y2 = q[3];
            diff[x1][y1]++;
            diff[x2 + 1][y1]--;
            diff[x1][y2 + 1]--;
            diff[x2 + 1][y2 + 1]++;
        }
        vector<vector<int>> ans(n, vector<int>(n));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                ans[i][j] = diff[i][j] 
                            + (i == 0 ? 0 : ans[i - 1][j])
                            + (j == 0 ? 0 : ans[i][j - 1])
                            - ((i == 0 || j == 0) ? 0 : ans[i - 1][j - 1]);
            }
        }
        return ans;
    }
};
Python
python 复制代码
'''
LastEditTime: 2025-11-14 19:16:40
'''
from typing import List

class Solution:
    def rangeAddQueries(self, n: int, queries: List[List[int]]) -> List[List[int]]:
        diff = [[0] * (n + 1) for _ in range(n + 1)]
        for x1, y1, x2, y2 in queries:
            diff[x1][y1] += 1
            diff[x2 + 1][y1] -= 1
            diff[x1][y2 + 1] -= 1
            diff[x2 + 1][y2 + 1] += 1
        ans = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(n):
                ans[i][j] = diff[i][j] + \
                            (0 if not i else ans[i - 1][j]) + \
                            (0 if not j else ans[i][j - 1]) - \
                            (0 if not i or not j else ans[i - 1][j - 1])
        return ans
Go
go 复制代码
/*
 * @Author: LetMeFly
 * @Date: 2025-11-14 19:38:51
 * @LastEditors: LetMeFly.xyz
 * @LastEditTime: 2025-11-14 19:46:39
 */
package main

func rangeAddQueries(n int, queries [][]int) [][]int {
    diff := make([][]int, n + 1)
    for i := range diff {
        diff[i] = make([]int, n + 1)
    }
    for _, q := range queries {
        x1, y1, x2, y2 := q[0], q[1], q[2], q[3]
        diff[x1][y1]++
        diff[x2 + 1][y1]--
        diff[x1][y2 + 1]--
        diff[x2 + 1][y2 + 1]++
    }

    ans := make([][]int, n)
    for i := range ans {
        ans[i] = make([]int, n)
    }
    for i := range ans {
        for j := range ans[i] {
            up := 0
            if i > 0 {
                up = ans[i - 1][j]
            }
            left := 0
            if j > 0 {
                left = ans[i][j - 1]
            }
            lu := 0
            if i > 0 && j > 0 {
                lu = ans[i - 1][j - 1]
            }
            ans[i][j] = diff[i][j] + left + up - lu
        }
    }
    return ans
}

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源

相关推荐
Charlie_lll1 分钟前
力扣解题-移动零
后端·算法·leetcode
chaser&upper1 分钟前
矩阵革命:在 AtomGit 解码 CANN ops-nn 如何构建 AIGC 的“线性基石”
程序人生·算法
weixin_4997715510 分钟前
C++中的组合模式
开发语言·c++·算法
iAkuya41 分钟前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼41 分钟前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck43 分钟前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl
松☆1 小时前
CANN与大模型推理:在边缘端高效运行7B参数语言模型的实践指南
人工智能·算法·语言模型
java干货1 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
皮皮哎哟1 小时前
数据结构:嵌入式常用排序与查找算法精讲
数据结构·算法·排序算法·二分查找·快速排序
程序员清洒1 小时前
CANN模型剪枝:从敏感度感知到硬件稀疏加速的全链路压缩实战
算法·机器学习·剪枝