当前位置: 首页 > ds >正文

二维前缀和问题

文章目录

  • 问题描述
  • 暴力解法
    • 暴力解法的问题
  • 前缀和优化
    • 核心思想
    • 前缀和构建过程
    • 查询计算过程
  • 性能对比

问题描述

今天在牛客上刷算法题时,碰到这样一道题,题目要求我们用前缀和解题,但是我并没有太深入了解过这个算法,于是只能暴力求解,但是发现提交后都显示超时或有些案例不通过,我百思不得其解,于是通过网上的搜索和看题解的方法终于对前缀和问题有了清晰的认识。
题目如下:
在这里插入图片描述
请你计算该子矩阵中全部元素之和,记为:

S(x1,y1,x2,y2)=∑i=x1x2∑j=y1y2ai,jS(x1, y1, x2, y2) = \sum_{i=x1}^{x2} \sum_{j=y1}^{y2} a_{i,j}S(x1,y1,x2,y2)=i=x1x2j=y1y2ai,j
这时候,二维前缀和 就派上用场了。

暴力解法

看到这题,最直观的想法就是:每次查询都遍历指定区域,把所有元素加起来。

import java.util.Scanner;public class ForceMatrix {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int m = scanner.nextInt();int q = scanner.nextInt();int[][] matrix = new int[n + 1][m + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {matrix[i][j] = scanner.nextInt();}}for (int k = 0; k < q; k++) {int x1 = scanner.nextInt();int y1 = scanner.nextInt();int x2 = scanner.nextInt();int y2 = scanner.nextInt();// 暴力遍历指定区域long sum = 0;for (int i = x1; i <= x2; i++) {for (int j = y1; j <= y2; j++) {sum += matrix[i][j];}}System.out.println(sum);}scanner.close();}
}

暴力解法的问题

时间复杂度分析
每次查询最坏需要遍历整个矩阵:O(n × m),q 次查询总时间复杂度:O(q × n × m),那么当 n = m = 10³,q = 10⁶ 时,总操作次数达到 10¹² 次,这是相当的耗时,所以我们要寻找优化方法。

前缀和优化

核心思想

与其每次查询都重新计算,不如先预处理出所有前缀和,让每次查询都能在 O(1) 时间内完成。

package com.coldscholor.prefix;import java.util.Scanner;/*** @author 寒士obj* @date 2025/08/10 21:34**/
// 2D前缀和
public class TwoPrefixSum1 {/*** 公式:s[i][j] = a[i][j] + s[i-1][j] + s[i][j-1] - s[i-1][j-1]* @param args*/public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int m = in.nextInt();int q = in.nextInt();long[][] a = new long[n + 1][m + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {a[i][j] = in.nextLong();}}long[][] sum = new long[n + 1][m + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {sum[i][j] = a[i][j] + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];}}while (q-- > 0){int x1 = in.nextInt();int y1 = in.nextInt();int x2 = in.nextInt();int y2 = in.nextInt();System.out.println(sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1]);}}
}

前缀和构建过程

假设我们有这样一个 3×3 矩阵:

原矩阵:
1  2  3
4  5  6  
7  8  9构建前缀和(每个位置存储从(1,1)到当前位置的矩形和):
1   3   6
5  12  21
12 27  45

公式:prefix[i][j] = a[i][j] + prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1]

查询计算过程

要查询区域 (2,2) 到 (3,3) 的和:

目标区域:    需要的计算:2  3        prefix[3][3] = 45 (大矩形)5  6      - prefix[1][3] = 6  (上方多余)8  9      - prefix[3][1] = 12 (左方多余)  + prefix[1][1] = 1  (重复减去的左上角)= 45 - 6 - 12 + 1 = 28

目标区域是 (2,2) 到 (3,3),即元素 5, 6, 8, 9之和为28,验证这个公式是正确的。

性能对比

方法预处理时间查询时间总时间复杂度
暴力解法O(1)O(n×m)O(q×n×m)
前缀和优化O(n×m)O(1)O(n×m + q)

实际效果
当 n = m = 1000, q = 100000 时,前缀和优化:10⁶ + 10⁵ ≈ 10⁶ 次操作(轻松AC)。

http://www.xdnf.cn/news/17672.html

相关文章:

  • 如何在 Ubuntu 24.04 LTS Linux 上安装 MySQL 服务器
  • 电脑本地摄像头做成rtsp流调用测试windows系统中
  • 【大智慧数据】心智开花的时候
  • AI测试助手如何让Bug无处可藏
  • Dify 从入门到精通(第 26/100 篇):Dify 的知识图谱集成
  • 2025最新免费的大模型和免费的大模型API有哪些?(202508更新)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python二级)真题及答案
  • 【Linux指南】Vim的全面解析与深度应用
  • C语言第八章指针四
  • 【接口自动化】初识pytest,一文讲解pytest的安装,识别规则以及配置文件的使用
  • Jotai:React轻量级状态管理新选择
  • Code Exercising Day 10 of “Code Ideas Record“:StackQueue part02
  • SQL三剑客:DELETE、TRUNCATE、DROP全解析
  • CentOS7.9 离线安装mysql数据库
  • CPP继承
  • Windows执行kubectl提示拒绝访问【Windows安装k8s】
  • `sk_buff` 结构体详解(包含全生命周期解析)
  • 数学建模:控制预测类问题
  • 全面了解机器语言之kmeans
  • 010601抓包工具及证书安装-基础入门-网络安全
  • 【Matplotlib】中文显示问题
  • 企业级WEB应用服务器TOMCAT — WEB技术详细部署
  • 正点原子esp32s3探测土壤湿度
  • openpnp - 顶部相机如果超过6.5米影响通讯质量,可以加USB3.0信号放大器延长线
  • Effective C++ 条款34:区分接口继承和实现继承
  • 数据库面试题集
  • DFT的几点理解(二)
  • 计算二分类误差时的常见错误及解决方案
  • 农经权二轮延包—已有软件与后续研究
  • Spring之【详解AOP】