算法:图解前缀和问题

文章目录

  • 实现原理
  • 实现思路
    • 一维前缀和模板
    • 二维前缀和模板
  • 典型例题
    • 一维前缀和
    • 二维前缀和
    • 寻找数组中心下标
    • 除自身以外数组的乘积
    • 关系矩阵和
  • 总结

实现原理

前缀和问题和二分查找类似,也是有一些固定的模板的,在理解原理的基础上进行实践,就能解决大多数问题

前缀和问题的题目问法通常是计算某个序列中子序列的之和,如果采用暴力求解的话就是遍历一遍数组,假设要找M个子序列,序列长度总共为N,那么时间复杂度就是O(M*N),而前缀和算法原理可以优化这个时间复杂度

实现原理有些类似于动态规划,原理就是预处理一个前缀和数组,然后利用前缀和数组解决问题即可

下面介绍算法的实现思路

实现思路

在这里插入图片描述

现在我们有数组arr,要求的结果是取出qarr中的子序列,计算这些子序列的长度,算法原理开辟一个和arr一样大的数组,作为dp数组,数组内存储的是对应arr中对应下标前所有位置数之和

一维前缀和模板

vector<long long> v(n+1);
for (int i = 1; i <= n; i++)
{cin>>v[i];
}
vector<long long> dp(n+1);
dp[0]=0;
for (int i = 1; i <= n; i++)
{dp[i]= dp[i - 1] + v[i];
}

自此,一维前缀和总体结束,下面是二维前缀和的题目解析

在这里插入图片描述

整体来看,二维前缀和和一维前缀和相差不算很大,代码实现的思路也很好想,可以图解如下表示

假设现在有下图所示的二维序列,这里面存储的是一些数据

在这里插入图片描述

依据题意,假设这里需要求4,3的内容,因此需要计算的是这片区域的面积

在这里插入图片描述
因此,我们可以仿照前面的算法,也用dp原理创建一个dp数组,数组中每一个元素存储的是从1,1到该位置这块区域内的所有元素的和

那么区间内数组如何计算?如果采用一个一个遍历找的时间复杂度显然是不合适的,因此需要找到一种更高效的复杂度方式,可以采用如下方式

在这里插入图片描述

对于我们要求的彩色区域,可以划分为四个子区域进行求解,那么面积如何求?如果采用A+B+C+D直接求,是不合理的,原因在于B和C的面积不能直观的求解,因此可以改成(A+C)+(A+B)+D-A,通过这样划分区域,就可以求解问题

抽象化上面的思路,假设要求i,j位置的值,就可以抽象化为dp[i][j]=dp[i-1][j]+dp[i][j-1]+arr[i][j]-dp[i-1][j-1]

那现在根据上面的算法原理,已经把dp数组求出来了,那么后续如何求解?

假设现在要求的是2,2,4,4,理论上所求区域如下在这里插入图片描述
那么对应到dp数组就是下面的区域

在这里插入图片描述

将整个区域进行抽象化演示,即看成从m,np,q

因此这个区域面积就可以表示为dp[m][n]-dp[p-1][q]-dp[p][q-1]+dp[p-1][q-1]

因此,二维前缀和的做题思路就抽象化出来了,首先用dp数组表示出一个和数组,再利用和数组面积的加减关系求解出最终答案即可

二维前缀和模板

// 数据输入
for (int i = 1; i <= m; i++)
{for (int j = 1; j <= n; j++){cin >> v[i][j];}
}
// 处理dp数组
vector<vector<long long>> dp(m + 1, vector<long long>(n + 1));
for (int i = 1; i <= m; i++)
{for (int j = 1; j <= n; j++){dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + v[i][j] - dp[i - 1][j - 1];}
}

典型例题

一维前缀和

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;int main()
{int n, q;cin >> n >> q;vector<long long> v(n+1);for (int i = 1; i <= n; i++){cin>>v[i];}vector<long long> dp(n+1);dp[0]=0;for (int i = 1; i <= n; i++){dp[i]= dp[i - 1] + v[i];}while (q--){int l, r;cin >> l >> r;cout << dp[r] - dp[l - 1] << endl;}return 0;
}

二维前缀和

在这里插入图片描述

#include <iostream>
#include <vector>
using namespace std;int main()
{int m = 3, n = 4, q = 3;cin >> m >> n >> q;vector<vector<int>> v(m + 1,vector<int>(n+1));// 数据输入for (int i = 1; i <= m; i++){for (int j = 1; j <= n; j++){cin >> v[i][j];}}// 处理dp数组vector<vector<long long>> dp(m + 1, vector<long long>(n + 1));for (int i = 1; i <= m; i++){for (int j = 1; j <= n; j++){dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + v[i][j] - dp[i - 1][j - 1];}}// 处理数据while (q--){int x1, y1, x2, y2;cin >> x1 >> y1 >> x2 >> y2;cout << dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1 - 1][y1 - 1] << endl;}return 0;
}

寻找数组中心下标

在这里插入图片描述

本题应用了前缀和的思路,写入两个表,一个从后向前写,一个从前向后写,其中要注意对于这个题的边界下标问题,尤其是从右向左写容易越界

处理前缀和问题要想清楚,前后缀和数组的含义是当前下标之前/后元素,不含当前下标元素

class Solution 
{
public:int pivotIndex(vector<int>& nums) {int n=nums.size();// 处理前缀和vector<int> f(n);f[0]=0;for(int i=1;i<n;i++){f[i]=f[i-1]+nums[i-1];}// 处理后缀和vector<int> g(n);g[n-1]=0;for(int i=n-2;i>=0;i--){g[i]=g[i+1]+nums[i+1];}// 处理数据for(int i=0;i<n;i++){if(f[i]==g[i]){return i;}}return -1;}
};

除自身以外数组的乘积

在这里插入图片描述

此题也是很明显的前缀和问题,在解题的时候,要理清思路,一要处理好边界问题,二要想清楚原理,边界问题提前处理

class Solution 
{
public:vector<int> productExceptSelf(vector<int>& nums){int n = nums.size();// 前缀和数组vector<int> f(n);f[0] = 1;for (int i = 1; i < n; i++){f[i] = f[i - 1] * nums[i - 1];}// 后缀和数组vector<int> g(n);g[n - 1] = 1;for (int i = n - 2; i >= 0; i--){g[i] = g[i + 1] * nums[i + 1];}// 返回数组vector<int> res(n);res[0] = g[0];res[n - 1] = f[n - 1];for (int i = 1; i < n - 1; i++){res[i] = f[i] * g[i];}return res;}
};

关系矩阵和

在这里插入图片描述

二维数组的前缀和问题中的简单应用,其中关于二维数组前缀和主要就是要注意dp数组的写入,在这个过程中涉及到的边界问题,其余如果理解原理应用模板是可以很好解决的

class Solution 
{
public:vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {int m=mat.size();int n=mat[0].size();// 创建前缀和二维数组vector<vector<int>> dp(m+1,vector<int>(n+1));for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mat[i-1][j-1];}}// 算数据vector<vector<int>> ans(m,vector<int>(n));for(int i=0;i<m;i++){for(int j=0;j<n;j++){int x1=max(0,i-k)+1,y1=max(0,j-k)+1;int x2=min(m,i+k+1),y2=min(n,j+k+1);ans[i][j]=dp[x2][y2]-dp[x2][y1-1]-dp[x1-1][y2]+dp[x1-1][y1-1];}}return ans;}
};

总结

前缀和问题也是较为重要的算法,重点就是要理解dp数组的意义,尤其是对于二维数组的前缀和,要理解才能正确写出

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Git】学习总结

【Git】学习总结 【一】安装【二】Git克隆项目代码【1】idea下载git项目【2】创建新的分支【3】新建的分支推送到远程【4】合并最新代码到主分支【5】切换分支 【三】提交本地项目到远程&#x1f680;1. 配置 Git&#x1f680;2. 创建项目远程仓库&#x1f680;3. 初始化本地仓…

MybatisPlus(1)

前言&#x1f36d; ❤️❤️❤️SSM专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 MyBatis-Plus&#xff08;简称MP&#xff09;是一个 Mybatis 的增强工具&…

70吨服务区生活污水处理设备加工厂家电话

70吨服务区生活污水处理设备加工厂家电话 设备简单说明 调节池 由于来水标高低&#xff0c;无法直接流入地埋式生活污水处理设备&#xff0c;在生化一体化设备前增加集水调节池一座。集水提升池内装有两台潜水提升泵&#xff0c;将集水提升池内的废水提升至一体化污水处理设备。…

后端项目开发:集成Druid数据源

Druid作为连接池中间件可以监控数据库访问性能&#xff0c;对数据库密码加密&#xff0c;查看SQL执行日志&#xff0c;扩展JDBC。 添加依赖 <!-- druid --> <dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter&…

unity动画融合

1、抛砖引玉 在大型复杂的场景中&#xff0c;一定遇到过手在鼓掌&#xff0c;头在摇头&#xff0c;腿又是其他动作的要求&#xff0c;但是这些东西又不能做一起&#xff0c;因为有时候要把某个动画单独使用&#xff0c;这时候就用到了动画融合&#xff0c;利用动画状态机分层机…

Java——简单的文件读取和写入

这段代码是一个简单的文件读取和写入的例子。它创建了一个BufferFile类&#xff0c;构造方法接受一个文件名作为参数。BufferFile类中的write方法用于从标准输入读取内容&#xff0c;并将其写入到指定的文件中&#xff0c;直到输入"end"为止。read方法用于读取指定文…

限时 180 天,微软为 RHEL 9 和 Ubuntu 22.04 推出 SQL Server 2022 预览评估版

导读近日消息&#xff0c;微软公司今天发布新闻稿&#xff0c;宣布面向 Red Hat Enterprise Linux&#xff08;RHEL&#xff09;9 和 Ubuntu 22.04 两大发行版&#xff0c;以预览模式推出 SQL Server 2022 评估版。 近日消息&#xff0c;微软公司今天发布新闻稿&#xff0c;宣布…

【力扣】59. 螺旋矩阵 II <模拟>

【力扣】59. 螺旋矩阵 II 给你一个正整数 n n n &#xff0c;生成一个包含 1 到 n 2 n^2 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n n n n nn 正方形矩阵 m a t r i x matrix matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,…

docker以distribution和registry管理个人镜像仓库

目录 一.distribution 1.扩展源下载docker-distribution并启动 2.打标签并认证安全仓库 3.推送到私人仓库 4.拉取镜像 二.registry 1.拉取registry的镜像 2.运行容器并打标签 3.认证安全仓库 4.推送到私人仓库 5.拉取镜像 一.distribution 1.扩展源下载docker-dist…

leetcode 767. Reorganize String(重组字符串)

重新排列字符串s中的字母&#xff0c;使得任意两个相邻的字母都不相同。 思路&#xff1a; 让相邻字母不同&#xff0c;能想到的办法是先把相同的字母排列&#xff0c; 然后在相同字母的缝隙中插入另一种字母。 比如"aab", 先把"a a"排出来&#xff0c;再…

20-GIT版本控制

GIT 一 简介 场景 团队协作的时候,我们项目开发会遇到代码需要进行管理的场景。 多个开发者之间,每天写的代码可能需要合并,共享。 例子:我写的用户模块、小王写的订单模块,用户模块最终需要跟订单模块合并。 每天写完代码,qq、u盘拷贝,代码合并一个项目中。 希望…

RabbitMQ---订阅模型-Fanout

1、 订阅模型-Fanout Fanout&#xff0c;也称为广播。 流程图&#xff1a; 在广播模式下&#xff0c;消息发送流程是这样的&#xff1a; 1&#xff09; 可以有多个消费者 2&#xff09; 每个消费者有自己的queue&#xff08;队列&#xff09; 3&#xff09; 每个队列都要绑定…

深度学习1.卷积神经网络-CNN

目录 卷积神经网络 – CNN CNN 解决了什么问题&#xff1f; 需要处理的数据量太大 保留图像特征 人类的视觉原理 卷积神经网络-CNN 的基本原理 卷积——提取特征 池化层&#xff08;下采样&#xff09;——数据降维&#xff0c;避免过拟合 全连接层——输出结果 CNN …

视频云存储/安防监控视频AI智能分析网关V3:抽烟/打电话功能详解

人工智能技术已经越来越多地融入到视频监控领域中&#xff0c;近期我们也发布了基于AI智能视频云存储/安防监控视频AI智能分析平台的众多新功能&#xff0c;该平台内置多种AI算法&#xff0c;可对实时视频中的人脸、人体、物体等进行检测、跟踪与抓拍&#xff0c;支持口罩佩戴检…

2023年下软考信息安全工程师报名时间及汇总(附备考攻略)

信息安全工程师是近几年新增的中级考试科目&#xff0c;一般在下半年考试&#xff0c;难度还是有的&#xff0c;但是只要你有恒心&#xff0c;愿意付出&#xff0c;认真刷题备考&#xff0c;拿下证书还是没有问题的&#xff01; 2023年下半年由于考试改革&#xff0c;报名时间…

【ArcGIS微课1000例】0072:如何生成空间权重矩阵

严重声明:本文来自专栏《ArcGIS微课1000例:从点滴到精通》,为CSDN博客专家刘一哥GIS原创,原文及专栏地址为:(https://blog.csdn.net/lucky51222/category_11121281.html),谢绝转载或爬取!!! 文章目录 一、空间权重矩阵工具介绍二、ArcGIS生成空间权重矩阵三、注意事项…

npm 安装 git 仓库包

安装 #v1.0.0 代表版本, 例如打了仓库一个tag叫v1.0.0; 如果不指定版本则默认是最新的代码仓库代码要包含打过包的代码page.json 要配置好相关字段, 按照npm包的格式就好 npm install githttp://mygitlab.xxxx.net/chengchongzhen/hex-event-track.git#v1.0.0其他方式, 将仓库代…

35. 搜索插入位置(简单系列)

给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输出: 2 示例 2: 输入…

用 Audacity 比较两段音频差异

工作中遇到相同的处理流程&#xff0c;处理同一段音频&#xff0c;看看处理结果是否一致&#xff0c;可以用audacity来处理。 假设待比较的音频分别为 1.wav 2.wav 1、用Audacity打开1.wav 2、用Audacity打开2.wav&#xff0c;选中音频&#xff0c;然后用 效果 -> 反向&am…

Leetcode77. 组合

给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 回溯剪枝 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 class Solution {public List<List<Integer>> combine(int n, i…