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

算法:前缀和算法模版

一维前缀和

题目

链接:一维前缀和模版题

在这里插入图片描述


思路分析

一:暴力O(q * N)
对于每一次询问,我们都可以用一个循环计算[l,r]区间内的元素和,
时间复杂度,O(q * N)

每一次计算一个区间都需要去循环一次,这是不是非常的麻烦呢?
我们能不能想一个办法把这个某个区间的和给存起来呢?进行反复利用呢?

所以,就优化出了,前缀和算法

二:前缀和O(q + N)

我们可以预处理出一个dp数组,来存放[1,i]的区间的元素和

当我们需要求区间[l,r]的元素和的时候,就可以用dp[r] - dp[l - 1]
这样每次查询的时候,时间复杂度就是O(1)

那么我们怎么去预处理出这个dp数组呢?
我们可以用递推的思想,前n个元素的和等于前n-1个元素的和加上第n个元素的和
所以,dp[i[ = dp[i - 1] + arr[i]

细节:
这里的下标是从1,开始,如果从0开始需要对dp[0]特殊处理一下。


代码

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int n ,q;
    cin >> n >> q;

    vector<int> a(n+1);
    vector<long long> dp(n+1);

    for(int i = 1;i < n + 1;i++)
    {
        cin >> a[i];
        dp[i] = dp[i-1] + a[i]; 
    }

    while(q--)
    {
        int l,r;
        cin >> l >> r;
        cout << dp[r] - dp[l-1] << endl;
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

二维前缀和

题目

链接:二维前缀和模版题

在这里插入图片描述


思路分析

暴力的时间复杂度是O(q * n2),很容易想,就不多叙述了。
直接讲一下二维前缀和算法的思路。

二维前缀和与一维前缀和类似,都是采用拼接的思路。
我们先预处理出来一个dp数组,用来存放从[1,1]到[i,j]这个矩阵内的元素和。

在这里插入图片描述
来,我们抽象出来一个矩阵,从[1,1]到[i,j]

如何去求这个区间的和呢?
很明显A + B + C + D对吧
但是B 和 C都不好求啊,
诶嘿,来,试试小学几何题常用的割补法。
我们可以将A+B看成一个整体,将A+C看成一个整体
那么A+B+C+D = (A+B)+(A+C)- A + D
具象到代码就是
dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + arr[i][j]

好,预处理完dp数组后,我们如何去使用dp数组去求任意一个矩阵的元素和呢?

假设我们就需要求D区间的元素和(假设左上顶点是x1,y1,右下顶点是x2,y2)
很容易想到的是,(A+B+C+D) - (A+B+C)
但是,和之前一样,B和C区间处理不了,依然采用割补法。
D = (A+B+C+D) - (A+B) - (A+C) + A
具象到代码就是
answer = dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1]

此时的时间复杂度是O(N2 + q)

细节:下标也是从1开始,dp数组多开一个空间,开到n+1,m+1
如果下标是从0开始,需要对边界情况进行特殊处理


代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n,m,q;
    cin >>n >> m>> q;
    vector<vector<int>> a(n+1,vector<int>(m+1));
    vector<vector<long long>> dp(n+1,vector<long long>(m+1));

    for(int i = 1;i<n+1;++i)
    {
        for(int j = 1;j< m+1;++j)
        {
            cin >> a[i][j];
            dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + a[i][j];
        }
    }

    while(q--)
    {
        int x1,y1,x2,y2;
        cin >> x1 >> y1 >> x2 >>y2;
        cout << dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1] << endl;
    }

    return 0;
}

国庆节结束了,我又回来啦,hhh,
继续更新!!!


http://www.kler.cn/news/339268.html

相关文章:

  • [笔记] 仿射变换性质的代数证明
  • PyQt入门指南一 框架介绍
  • 一分钟掌握 Java22 新特性
  • STM32-HAL库 驱动DS18B20温度传感器 -- 2024.10.8
  • 数据结构——排序(插入排序)
  • VAD 论文学习
  • 每日OJ题_牛客_分组_枚举+二分_C++_Java
  • OpenFeign 工作原理源码记录
  • OpenFegin
  • 【多重循环在Java中的应用】
  • 【如何学习计组】——基本概念与原理
  • 大数据新视界 --大数据大厂之数据血缘追踪与治理:确保数据可追溯性
  • windows配置java环境变量
  • 基于java+springboot的宠物商店、宠物管理系统
  • 大数据新视界 --大数据大厂之 Presto 性能优化秘籍:加速大数据交互式查询
  • LeetCode:134. 加油站(Java 贪心)
  • 【笔记】DDD领域驱动设计
  • 在一台电脑上实现网页与exe程序使用udp通信
  • Overleaf 无法显示图片
  • Spring Data(学习笔记)