二维前缀和数组二维差分数组

news/2023/6/9 18:24:23

二维前缀和数组&二维差分数组

一维前缀和

  • 用途:快速求出数组中nums[i,j]nums[i,j]nums[i,j]元素之和

  • 定义:sums[i+1]sums[i+1]sums[i+1]nums数组前iii个元素之和
    sums[i+1]=∑j=0inums[j]sums[i + 1] = \sum _{j=0} ^{i}nums[j] sums[i+1]=j=0inums[j]

  • 因此,可以快速计算出数组中nums[i,j]nums[i,j]nums[i,j]元素之和为sum[j+1]−sum[i]sum[j+1]-sum[i]sum[j+1]sum[i]

一维差分

  • 定义:差分数组的每一项都是原数组该项与上一项的差
    d[i]=a[i]−a[i−1]d[i]=a[i]-a[i-1] d[i]=a[i]a[i1]

  • 用途:常用于区间修改,如对原始数组a[n]内一段区间上的数值进行加减操作,则:

    • 在差分数组d[n]选定区间[l,r],确认加减数值x

    d[l]+=xd[r+1]−=xd[l] += x \\d[r+1] -= x d[l]+=xd[r+1]=x

    • 然后对该数组求累加和数组,就得到了变化后的数组
  • 例如

    index012345
    原始数组023758
    原差分数组0214-23
    操作:对区间[1,3]+35610
    现差分数组0514-53
    累加和数组0561058

二维前缀和

  • 「二维前缀和」解决的是二维矩阵中的矩形区域求和问题。

  • 二维前缀和数组中的每一个格子记录的是「**以当前位置为区域的右下角(区域左上角恒定为原数组的左上角)**的区域和」【应该不固定 可以倒转】
    sum[i,j]=sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1]+matrix[i][j]sum[i,j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+matrix[i][j] sum[i,j]=sum[i1][j]+sum[i][j1]sum[i1][j1]+matrix[i][j]
    1.png

  • 因此,如果要求 (x1, y1) 作为左上角,(x2, y2) 作为右下角的区域和的时候,可以直接利用二维前缀和数组快速求解:
    res=sum[x2][y2]−sum[x1−1][y2]−sum[x2][y1−1]+sum[x1−1][y1−1]res=sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1] res=sum[x2][y2]sum[x11][y2]sum[x2][y11]+sum[x11][y11]

二维差分

  • 「二维差分」解决的是二维矩阵中的矩形区域值的变化问题。

  • 两种情况:以当前位置为左上角或右下角

  • 左上角

    • 二维数组某个位置(x1,y1)(x1,y1)(x1,y1)的变化量,可由二维差分数组的二维前缀和数组得到,即以当前位置为左上角,原数组的右下角为右下角的区域和

    • 二维差分数组中的每一个格子记录的是「以当前位置为区域的右下角(区域左上角恒定为原数组的左上角)的值的变化量」【应该不固定 可以倒转】

    • 因此,如果要求 (x1,y1)(x1, y1)(x1,y1) 作为左上角,(x2,y2)(x2, y2)(x2,y2) 作为右下角的区域值增加xxx的时候,可以利用二维差分数组快速求解,此时相当于二维差分矩阵上对(x2,y2)(x2,y2)(x2,y2)增加xxx,对(x2,y1−1)(x2,y1-1)(x2,y11)(x1−1,y2)(x1-1,y2)(x11,y2)减小xxx,再对重复区域(x1−1,y1−1)(x1-1,y1-1)(x11,y11)增加xxx

    • 二维数组某个位置(x1,y1)(x1,y1)(x1,y1)的变化量,可由二维差分数组的二维前缀和数组sum得到,即以当前位置为左上角,原数组的右下角为右下角的区域和【倒叙求】
      sum[i,j]=sum[i+1][j]+sum[i][j+1]−sum[i+1][j+1]+dev[i][j]sum[i,j] = sum[i+1][j]+sum[i][j+1]-sum[i+1][j+1]+dev[i][j] sum[i,j]=sum[i+1][j]+sum[i][j+1]sum[i+1][j+1]+dev[i][j]

  • 右下角【常用】

    • 二维数组某个位置(x1,y1)(x1,y1)(x1,y1)的变化量,可由二维差分数组的二维前缀和数组得到,即以当前位置为右下角,原数组的左上角为左上角的区域和

    • 二维差分数组中的每一个格子记录的是「以当前位置为区域的左上角(区域右下角恒定为原数组的右下角)的值的变化量」【应该不固定 可以倒转】

    • 因此,如果要求 (x1,y1)(x1, y1)(x1,y1) 作为左上角,(x2,y2)(x2, y2)(x2,y2) 作为右下角的区域值增加xxx的时候,可以利用二维差分数组快速求解,此时相当于二维差分矩阵上对(x1,y1)(x1,y1)(x1,y1)增加xxx,对(x2+1,y1)(x2+1,y1)(x2+1,y1)(x1,y2+1)(x1,y2+1)(x1,y2+1)减小xxx,再对重复区域(x2+1,y2+1)(x2+1,y2+1)(x2+1,y2+1)增加xxx

    • 要求得二维数组每个位置(x1,y1)(x1,y1)(x1,y1)的变化量,即求二维差分数组的二维前缀和数组sum,即差分数组以当前位置为右下角,原数组的左上角为左上角的区域和
      sum[i,j]=sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1]+dev[i][j]sum[i,j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+dev[i][j] sum[i,j]=sum[i1][j]+sum[i][j1]sum[i1][j1]+dev[i][j]

  • 总结

    • 二维差分数组可视为以位置[i,j]为右下角原点为右上角的区域之和【二维前缀和数组sum[i][j]sum[i][j]sum[i][j]】与该区域除了位置[i,j]的区域和之差,用二维前缀和数组可表示为

    div[i][j]=sum[i][j]−sum[i−1][j]−sum[i][j−1]+sum[i+1][j+1]div[i][j]=sum[i][j] - sum[i-1][j]-sum[i][j-1]+sum[i+1][j+1] div[i][j]=sum[i][j]sum[i1][j]sum[i][j1]+sum[i+1][j+1]

    image-20230118214317962

    • 因此若已知二维数组a,求得其二维前缀和数组b,那么a即为b的差分数组
  • 用途:将某一区域的值进行变化,首先求出差分数组,然后对该求出二维前缀和数组,即可求得变化后的结果

  • 模板:由区域变化量求得二维差分数组,由二维差分数组求前缀和数组

    二维差分数组div中的每一个格子记录的是「以当前位置为区域的左上角(区域右下角恒定为原数组的右下角)的值的变化量」【应该不固定 可以倒转】

    二维差分数组的二维前缀和数组sum,即差分数组以当前位置为右下角,原数组的左上角为左上角的区域和

    • 初始时div数组需要扩展边界,转化为sum时需要处理0

      class Solution {public int[][] rangeAddQueries(int n, int[][] queries) {int[][] div = new int[n + 1][n + 1];for (int[] q : queries){div[q[0]][q[1]]++;div[q[0]][q[3] + 1]--;div[q[2] + 1][q[1]]--;div[q[2] + 1][q[3] + 1]++;}int[][] sum = new int[n][n];for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){sum[i][j] = div[i][j];if (i != 0) sum[i][j] += sum[i - 1][j];if (j != 0) sum[i][j] += sum[i][j - 1]; if (i != 0 && j != 0) sum[i][j] -= sum[i - 1][j - 1];}}return sum;}
      }
      
    • div数组边界可以+2,方便处理0

      div[1:n][1:n]div[1:n][1:n]div[1:n][1:n]计算为二维前缀和数组,在赋值给结果集

      class Solution {public int[][] rangeAddQueries(int n, int[][] queries) {int[][] div = new int[n + 2][n + 2];for (int[] q : queries){div[q[0] + 1][q[1] + 1]++;div[q[0] + 1][q[3] + 2]--;div[q[2] + 2][q[1] + 1]--;div[q[2] + 2][q[3] + 2]++;}int[][] sum = new int[n][n];for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){sum[i - 1][j - 1] = (div[i][j] += div[i - 1][j] + div[i][j - 1] - div[i - 1][j - 1]);}}return sum;}
      }
      
  • 模板:由前缀和数组求得二维差分数组即求出每个位置的数值

    	// sum n*n// div (n+1)*(n+1)//求出差分数组for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){div[i][j]=sum[i][j]-sum[i-1][j]-sum[i][j-1]+sum[i-1][j-1]; } 
    

相关题目

子矩阵元素加 1【LC2536】

给你一个正整数 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

暴力

java过了…

class Solution {public int[][] rangeAddQueries(int n, int[][] queries) {int[][] mat = new int[n][n];for (int[] query : queries){int row1 = query[0], col1 = query[1], row2 = query[2], col2 = query[3];for (int i = row1; i <= row2; i++){for (int j = col1; j <= col2; j++){mat[i][j]++;}}}return mat;}
}
  • 复杂度
    • 时间复杂度:O(n2∗q)O(n^2*q)O(n2q)qqqqueriesqueriesqueries的长度
    • 空间复杂度:O(1)O(1)O(1)

二维差分

前置知识:二维差分数组与二维前缀和数组

  • 思路:使用二维差分数组记录每个区域的变化量,然后通过二维前缀和数组求得每个位置的值

  • 实现

    • 二维差分数组div中的每一个格子记录的是「以当前位置为区域的左上角(区域右下角恒定为原数组的右下角)的值的变化量」【应该不固定 可以倒转】

    • 二维差分数组的二维前缀和数组sum,即差分数组以当前位置为右下角,原数组的左上角为左上角的区域和

    • 因此,如果要求 (x1,y1)(x1, y1)(x1,y1) 作为左上角,(x2,y2)(x2, y2)(x2,y2) 作为右下角的区域值增加xxx的时候,可以利用二维差分数组快速求解,此时相当于二维差分矩阵上对(x1,y1)(x1,y1)(x1,y1)增加xxx,对(x2+1,y1)(x2+1,y1)(x2+1,y1)(x1,y2+1)(x1,y2+1)(x1,y2+1)减小xxx,再对重复区域(x2+1,y2+1)(x2+1,y2+1)(x2+1,y2+1)增加xxx

    • 要求得二维数组每个位置(x1,y1)(x1,y1)(x1,y1)的变化量,即求二维差分数组的二维前缀和数组sum,即差分数组以当前位置为右下角,原数组的左上角为左上角的区域和
      sum[i,j]=sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1]+dev[i][j]sum[i,j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+dev[i][j] sum[i,j]=sum[i1][j]+sum[i][j1]sum[i1][j1]+dev[i][j]

      • 初始时div数组需要扩展边界,转化为sum时需要处理0

        class Solution {public int[][] rangeAddQueries(int n, int[][] queries) {int[][] div = new int[n + 1][n + 1];for (int[] q : queries){div[q[0]][q[1]]++;div[q[0]][q[3] + 1]--;div[q[2] + 1][q[1]]--;div[q[2] + 1][q[3] + 1]++;}int[][] sum = new int[n][n];for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){sum[i][j] = div[i][j];if (i != 0) sum[i][j] += sum[i - 1][j];if (j != 0) sum[i][j] += sum[i][j - 1]; if (i != 0 && j != 0) sum[i][j] -= sum[i - 1][j - 1];}}return sum;}
        }
        
        • 复杂度
          • 时间复杂度:O(n2+q)O(n^2+q)O(n2+q)qqqqueriesqueriesqueries的长度
          • 空间复杂度:O(1)O(1)O(1)
      • div数组边界可以+2,方便处理0

        div[1:n][1:n]div[1:n][1:n]div[1:n][1:n]计算为二维前缀和数组,在赋值给结果集

        class Solution {public int[][] rangeAddQueries(int n, int[][] queries) {int[][] div = new int[n + 2][n + 2];for (int[] q : queries){div[q[0] + 1][q[1] + 1]++;div[q[0] + 1][q[3] + 2]--;div[q[2] + 2][q[1] + 1]--;div[q[2] + 2][q[3] + 2]++;}int[][] sum = new int[n][n];for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){sum[i - 1][j - 1] = (div[i][j] += div[i - 1][j] + div[i][j - 1] - div[i - 1][j - 1]);}}return sum;}
        }
        
  • 进阶:子矩阵元素变化量不定

二维区域和检索 - 矩阵不可变【LC304】

Given a 2D matrix matrix, handle multiple queries of the following type:

  • Calculate the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

Implement the NumMatrix class:

  • NumMatrix(int[][] matrix) Initializes the object with the integer matrix matrix.
  • int sumRegion(int row1, int col1, int row2, int col2) Returns the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).

You must design an algorithm where sumRegion works on O(1) time complexity.

  • 思路:在构造方法中生成矩阵matrix的二维累加和数组,在sumRegion方法中通过累加和数组返回指定区域的和

  • 实现

    二维前缀和数组sum,即以当前位置为右下角,matrix数组的左上角为左上角的区域和

    为了方便处理边界0,将sum数组的周围扩展1

    class NumMatrix {int[][] sum;int m;int n;public NumMatrix(int[][] matrix) {m = matrix.length;n = matrix[0].length;sum = new int[m + 1][n + 1];for (int i = 0; i < m; i++){for (int j = 0; j < n; j++){sum[i + 1][j + 1] = sum[i][j + 1] + sum[i + 1][j] + matrix[i][j] - sum[i][j]; }}}public int sumRegion(int row1, int col1, int row2, int col2) {return sum[row2 + 1][col2 + 1] + sum[row1][col1] - sum[row1][col2 + 1] - sum[row2 + 1][col1];} 
    }/*** Your NumMatrix object will be instantiated and called as such:* NumMatrix obj = new NumMatrix(matrix);* int param_1 = obj.sumRegion(row1,col1,row2,col2);*/
    
    • 复杂度
      • 时间复杂度:构造方法的时间复杂度为生成二维前缀和数组的时间复杂度O(m∗n)O(m*n)O(mn),sumRegion的时间复杂度为O(1)O(1)O(1)
      • 空间复杂度:O(m∗n)O(m*n)O(mn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-4569635.html

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

C语言: 部署开发环境 —— c语言学习计划第一天

window10用MingW搭建C语言开发环境 部署环境&#xff1a;Window10 工具&#xff1a;mingw 下载地址&#xff1a;https://mingw.osdn.io/ 1.安装MingW 下载完成后得到mingw-get-setup.exe文件 双击打开进入安装界面 安装配置 安装完成后进入界面 Basic setup-> 右键选…

教学计划c语言源代码,c语言教学计划.doc

c语言教学计划.doc 1C语言程序设计课程教学实施计划一、课程简介课程学分4学分&#xff0c;其中理论3学分&#xff0c;实验1学分&#xff0c;课程学时数其中讲课44学时&#xff0c;实验112学时&#xff0c;开课专业及修课性质专业必修&#xff1b;。选课基础已学过二、课程任务…

C语言—循环语句超详解

文章目录前言一、while循环1.语法结构2.while循环中break的作用3.while循环中continue的作用二、for循环1.语法结构2.for循环和while循环对比三、do while循环1.语法结构2.语法特点3.do while循环中continue的作用四、演示案例(数字炸弹游戏)1.游戏介绍2.思路分析3.代码展示4.结…

智能五子棋-C语言

*一、项目需求* 五子棋是一种简单的黑白棋&#xff0c;历史悠久&#xff0c;起源于中国&#xff0c;后传入日本&#xff0c;在日本被称为“连珠”&#xff0c;是一种老少皆宜的益智游戏。 人工智能五子棋系统的目标用户是一切想致力于研究人机对弈算法理论的相关研究者和一切…

从零开始的C语言学习计划-初识C语言第一趴

首先来做一个简短的自我介绍 大家好&#xff0c;我是小王&#xff0c;目前为在读双非科班大学生&#xff0c;为了让今后的工作更加顺利&#xff0c;所以决定认真学习编程语言界的老大哥-C语言&#xff0c;为督促自己学习&#xff0c;决定以博客来总结我的学习情况&#xff0c…

系统设计必备-时序图

对于我一个新手学习&#xff0c;我觉得自己看看概念&#xff0c;然后照着前辈的时序图&#xff0c;照着代码自己认真过几遍&#xff0c;在学习前辈代码的同时&#xff0c;借助时序图你会学习的更快&#xff0c;理解的更全。对于新手分三个阶段就ok的 1&#xff1a;学习前辈的代…

J2EE电子政务门户系统

政府是全社会中最大的信息拥有者和最大的信息技术的用户&#xff0c;有效地利用信息技术&#xff0c;通过建立一个真正有效的、可伸缩的电子政务系统&#xff0c;可以帮助政府向更加勤政、精简、廉洁和高效的方向发展。电子政务将实现政务应用的四化方向&#xff1a;信息统一化…

Liferay开源门户系统之cas单点登录功能集成方法

目录 Liferay开源门户系统之cas单点登录功能集成方法 一、概述 二、cas服务端配置 步骤1&#xff1a;准备好以下运行环境 步骤2&#xff1a;安装部署cas-server 步骤3&#xff1a;生成数字证书 步骤4&#xff1a;配制tomcat支持https协议 步骤5&#xff1a;测试 三、liferay支持…