双指针+前缀和习题(一步步讲解)

前言:如果解决下面这几道题有些问题,或者即使看了我画的过程图也不理解的可以去看看我的上一篇文章,有可能会对你有帮助。


一、《数值元素的目标和》---来自AcWing  

数组元素的目标和
给定两个升序排序的有序数组 A和 B,以及一个目标值 。
数组下标从 0 开始
请你求出满足 A[i]+ B[j]=x 的数对(i,j)。
数据保证有唯一解。
输入格式:
第一行包含三个整数 n,m,x,分别表示 A 的长度,B 的长度以及目标值。
第二行包含 n 个整数,表示数组 A。
第三行包含 m 个整数,表示数组 B.
输出格式:
共一行,包含两个整数i和 j.
数据范围:
数组长度不超过 1e5
同一数组内元素各不相同。
1 ≤ 数组元素 < 1e9

输入样例:

4 5 6 

1 2 4 7

3 4 6 8 9

输出样例:

1 1

1.暴力解法

这道题暴力解法思路很简单,在这不过多赘述,直接上代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int arr[N], brr[N];
int n, m, x;
int main(void)
{scanf_s("%d%d%d", &n, &m, &x);for (int i = 0; i < n; i++)scanf_s("%d", &arr[i]);for (int i = 0; i < m; i++)scanf_s("%d", &brr[i]);for (int i = 0; i < n; i++){for (int j = 0; j < m; j++){if (arr[i] + brr[j] == x){cout << i << " " << j << endl;exit(0);}}}return 0;
}

分析暴力算法的时间复杂度:很明显O(n的平方),数组长度最大是1e5,所以时间复杂度准确为O(1e10),大于1e9,所以要开始想办法优化代码。

2.优化代码

1.画图分析

(看过我前面的文章的都知道我习惯用画图来疏通自己的思维逻辑)

 双指针:上面是两种思路进行分析,选取最方便最可行的方式,也就是第二种

2.打代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int arr[N], brr[N];
int n, m, x;
int main(void)
{scanf_s("%d%d%d", &n, &m, &x);for (int i = 0; i < n; i++)scanf_s("%d", &arr[i]);for (int i = 0; i < m; i++)scanf_s("%d", &brr[i]);for (int i = 0 , j = m-1; i < n ; i++){while (j >= 0 && arr[i] + brr[j] > x){j--;}if (arr[i] + brr[j] == x){cout << i << " " << j << endl;return 0;}}return 0;
}

仔细琢磨while循环所表达的意思,对照我所画的图进行分析,相信理解掌握这道题并不难

二、A-B数对---来自洛谷

给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式:

输入共两行。

第一行,两个正整数 N,C。

第二行,N 个正整数,作为要求处理的那串数

输出格式:

一行,表示该串正整数中包含的满足 A−B=C 的数对的个数。

输入样例:

4 1

1 1  2 3

输出样例:

3

1.暴力解法

2.优化代码

1.画图分析:

跟上个题一样,双指针的两种方式,从两个角度进行分析。

2.打代码

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int arr[N], cnt[N];
ll n, c;
int main(void)
{scanf_s("%lld%lld", &n, &c);ll res = 0;for (int i = 0; i < n; i++)scanf_s("%d", &arr[i]);for (int i = 0, j = 0; i < n; i++){while (j < n && arr[i] - arr[j] >= c){if (arr[i] - arr[j] == c){res++;}j++;}}cout << res << endl;return 0;
}

但是这样做是错误的。我们继续进行分析

3.进一步优化

重新找测试用例:

 

如果我画的图看不懂,可以自己尝试画一画,真的可以使自己的思路变得清晰明了

千万不要忘记排序!!!

 4.重新打代码

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int arr[N], cnt[N];
ll n, c;
int main(void)
{scanf_s("%lld%lld", &n, &c);ll res = 0;for (int i = 0; i < n; i++)scanf_s("%d", &arr[i]);sort(arr,arr+n);for (int i = 0, j1 = 0,j2 = 0; i < n; i++){while (j1 < n && arr[i] - arr[j1] >= c){j1++;}while (j2 < j1 && arr[i] - arr[j2] > c){ j2++;}res += (j1 - j2);}cout << res << endl;return 0;
}

三、递增三元组---来自洛谷

给定三个整数数组 A=[A1,A2,⋯ ,AN],B=[B1,B2,⋯ ,BN],C=[C1,C2,⋯ ,CN]

请你统计有多少个三元组 (i,j,k)(i,j,k) 满足:

  1. 1≤i,j,k≤N
  2. Ai<Bj<Ck

输入格式:

第一行包含一个整数 N。

第二行包含 N 个整数 A1,A2,⋯ ,AN

第三行包含 N 个整数 B1,B2,⋯ ,BN

第四行包含 N 个整数 C1,C2,⋯ ,CN

输出格式:

一个整数表示答案

输入样例:

3
1 1 1
2 2 2
3 3 3

输出样例:

27

1.暴力解法

思路也是很简单,三层循环枚举就可以

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int arr[N], brr[N], crr[N];
int main(void)
{int n;cin >> n;for (int i = 1; i <= n; i++)cin >> arr[i];for (int i = 1; i <= n; i++)cin >> brr[i];for (int i = 1; i <= n; i++)cin >> crr[i];//sort(arr + 1, arr + n + 1);//sort (brr + 1, brr + 1 + n);//sort(crr + 1, crr + 1 + n);long long res = 0;for (int i = 1; i <= n; i++){for (int j = 1; j <= n; j++){for (int k = 1; k <= n; k++){if (arr[i] < brr[j]&&brr[j] < crr[k])res++;}}}cout << res << endl;return 0;
}

2.优化代码

1.可以用二分查找来解决

这里我不多说关于二分的解题过程,还是将过程图画出来,大家感兴趣的可以看看,代码我也会给大家

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int n , a[N] , b[N] , c[N] , ans;
signed main(){cin >> n;for(int i = 1; i <= n; i++) cin >> a[i];for(int i = 1; i <= n; i++) cin >> b[i];for(int i = 1; i <= n; i++) cin >> c[i];sort(a + 1 , a + 1 + n);sort(c + 1 , c + 1 + n);//排序,好进行二分for(int j = 1; j <= n; j++){int cnta = lower_bound(a + 1 , a + 1 + n , b[j]) - a - 1;int cntc = upper_bound(c + 1 , c + 1 + n , b[j]) - c;cntc = n - cntc + 1;//二分找出i的种类数和j的种类数ans += cnta * cntc;//乘法原理累计答案}cout << ans;return 0;
}

自定义如下: 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int arr[N], brr[N], crr[N];
int n;
int binary1(int x)
{int l = 0, r = n + 1;while (l + 1 != r){int mid = (l + r) / 2;if (arr[mid] < brr[x])l = mid;else r = mid;}if (arr[l] < brr[x])return l;else return -1;
}
int binary2(int x)
{int l = 0, r = n + 1;while (l + 1 != r){int mid = (l + r) / 2;if (crr[mid] <= brr[x])l = mid;else r = mid;}if (crr[r] > brr[x])return r;else return -1;
}
int main(void)
{cin >> n;for (int i = 1; i <= n; i++)cin >> arr[i];for (int i = 1; i <= n; i++)cin >> brr[i];for (int i = 1; i <= n; i++)cin >> crr[i];sort(arr + 1, arr + n + 1);sort(brr + 1, brr + 1 + n);sort(crr + 1, crr + 1 + n);long long res = 0, tmp = 0;for (int i = 1; i <= n; i++){int x = binary1(i);int y = binary2(i);if (x == -1 || y == -1)continue;else{tmp = (long long)((x) * (n - y + 1));res += tmp;}}cout << res << endl;return 0;
}

2.用双指针来解决

想必认真做了前面两道题的同学,这道题画图之后也会有些思路,看一看自己写的和我写的有什么差别,及时订正!

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
typedef long long LL;
int a[N], b[N], c[N];
int main() {int n;cin >> n;for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]);sort(a + 1, a + n + 1);sort(b + 1, b + n + 1);sort(c + 1, c + n + 1);//先把数组排序,否则无法双指针 LL ans = 0;//不开long long见祖宗 int cnt = 1, cnt_ = 1;//双指针,记录a中小于b[i]的个数和c中不大于b[i]的个数 for (int i = 1; i <= n; i ++ ){while (cnt <= n && a[cnt] < b[i]) cnt ++;//查找a中小于b[i]的个数 while (cnt_ <= n && c[cnt_] <= b[i]) cnt_ ++;//为了方便。实际是在查找c中大于b[i]的个数 ans += (LL) (cnt - 1) * (n - cnt_ + 1); }cout << ans;return 0;
}

 四、求和----来自洛谷

题目描述:

给定 n 个整数 a1,a2,⋯ ,an, 求它们两两相乘再相加的和,即

S=a1⋅a2+a1⋅a3+⋯+a1⋅an+a2⋅a3+⋯+an−2⋅an−1+an−2⋅an+an−1⋅an

输入格式:

输入的第一行包含一个整数 nn 。

第二行包含 n 个整数 a1,a2,⋯an

输出格式:

输出一个整数 S,表示所求的和。请使用合适的数据类型进行运算。

输入输出样例

输入:

4
1 3 6 9

输出 :

117

对于 30% 的数据, 1≤n≤1000,1≤ai≤100 。

对于所有评测用例, 1≤n≤2×1e5,1≤ai≤1000 。

1.暴力解法

这道题的暴力解法就是两层循环,还是不过多赘述:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
int arr[N];
int n;
int main(void)
{cin >> n;for (int i = 1; i <= n; i++)cin >> arr[i];long long res = 0, tmp = 0;for (int i = 1; i <= n; i++){for (int j = i + 1; j <= n; j++){tmp += (arr[i] * arr[j]);res += tmp;}}cout << tmp << endl;return 0;
}

不过对于这道题来说,暴力解题只能得30分

2.前缀和解法

很明显:我们只要知道怎样求S[n]就能很完美的做出这道题 S[n]的求解就用到了前缀和算法思想

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
int arr[N], s[N];
int n;
int main(void)
{cin >> n;long long res = 0;for (int i = 1; i <= n; i++){cin >> arr[i];s[i] = s[i-1] + arr[i];}for (int i = 1; i <= n; i++){res += (arr[i]*(long long)(s[n]-s[i]));//千万千万别忘记开long long}cout << res << endl;return 0;
}

 


最后:真心希望这篇文章对你有所帮助!

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

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

相关文章

单调栈详解

文章目录 单调栈详解一、引言二、单调栈的基本原理1、单调栈的定义2、单调栈的维护 三、单调栈的应用场景四、使用示例1、求解下一个更大元素2、计算柱状图中的最大矩形面积 五、总结 单调栈详解 一、引言 单调栈是一种特殊的栈结构&#xff0c;它在栈的基础上增加了单调性约束…

分布式光纤应变监测是一种高精度、分布式的监测技术

一、土木工程领域 桥梁结构健康监测 主跨应变监测&#xff1a;在大跨度桥梁的主跨部分&#xff0c;如悬索桥的主缆、斜拉桥的斜拉索和主梁&#xff0c;分布式光纤应变传感器可以沿着这些关键结构部件进行铺设。通过实时监测应变情况&#xff0c;能够精确捕捉到车辆荷载、风荷…

《安富莱嵌入式周报》第349期:VSCode正式支持Matlab调试,DIY录音室级麦克风,开源流体吊坠,物联网在军工领域的应用,Unicode字符压缩解压

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; 《安富莱嵌入式周报》第349期&#xff1a;VSCode正式支持Matlab调试&#xff0c;DIY录音室级麦克风…

Pyside6(PyQT5)中的QTableView与QSqlQueryModel、QSqlTableModel的联合使用

QTableView 是QT的一个强大的表视图部件&#xff0c;可以与模型结合使用以显示和编辑数据。QSqlQueryModel、QSqlTableModel 都是用于与 SQL 数据库交互的模型,将二者与QTableView结合使用可以轻松地展示和编辑数据库的数据。 QSqlQueryModel的简单应用 import sys from PySid…

uniapp+Vue3(<script setup lang=“ts“>)模拟12306城市左右切换动画效果

效果图&#xff1a; 代码&#xff1a; <template><view class"container"><view class"left" :class"{ sliding: isSliding }" animationend"resetSliding">{{ placeA }}</view><view class"center…

VUE elTree 无子级 隐藏展开图标

这4个并没有下级节点&#xff0c;即它并不是叶子节点&#xff0c;就不需求展示前面的三角展开图标! 查阅官方文档如下描述&#xff0c;支持bool和函数回调处理&#xff0c;这里咱们选择更灵活的函数回调实现。 给el-tree结构配置一下props&#xff0c;注意&#xff01; :pr…

Ansys Motor-CAD:IPM 电机实验室 - 扭矩速度曲线

各位电动机迷们&#xff0c;大家好&#xff1a; 在本博客中&#xff0c;我讨论了如何使用 Ansys Motor-CAD 通过 LAB 模块获取扭矩速度曲线。使用每安培最大扭矩电机控制策略&#xff0c;并涵盖恒定扭矩区域和恒定功率、磁通减弱区域。分析了高转子速度如何影响功率输出。 模型…

网络(三) 协议

目录 1. IP协议; 2. 以太网协议; 3. DNS协议, ICMP协议, NAT技术. 1. IP协议: 1.1 介绍: 网际互连协议, 网络层是进行数据真正传输的一层, 进行数据从一个主机传输到另一个主机. 网络层可以将数据主机进行传送, 那么传输层保证数据可靠性, 一起就是TCP/IP协议. 路径选择: 确…

docker ubuntu:20.04构建c++ grpc环境

由c grpc必须源码编译&#xff0c;ubuntu版本不同可能出现的问题也不同&#xff0c;这里分享下我的构建过程。 我是vscode结合docker去安装c虚拟环境&#xff0c;我不想污染本机环境。 vscode的插件Dev Containers Dockerfile如下(如果单纯是ubuntu环境构建&#xff0c;可忽略该…

数据结构:二叉树—面试题(一)

目录 1、相同的树 2、另一棵树的子树 3、翻转二叉树 4、平衡二叉树 5、对称二叉树 6、二叉树遍历 7、二叉树的分层遍历 1、相同的树 习题链接https://leetcode.cn/problems/same-tree/description/https://leetcode.cn/problems/same-tree/description/ 描述&#xff1a…

MySQL训练营-慢查询诊断问题

慢查询相关参数和建议配置 slow_query_log long_query_time 日志开关&#xff0c;是否记慢查询日志以及超过多长时间判定为慢查询。 查看参数设置&#xff1a; SHOW VARIABLES LIKE ‘slow_query_log’;SHOW VARIABLES LIKE ‘long_query_time’; 实践建议&#xff1a; …

用edge浏览器追剧音量太小?安装音量增强器可解忧

0 源起 春节佳节将至&#xff0c;可以利用这个难得的假期追一追想看而没空看的剧了。 但是在用Edge浏览器播放网页中的视频时&#xff0c;有时音量太小&#xff0c;根本没法听清楚&#xff0c; 遇到这种情况时&#xff0c;尽管Edge浏览器本身没有提供音量控制功能&#xff0…

Linux-arm(1)ATF启动流程

Linux-arm(1)ATF启动流量 Author&#xff1a;Once Day Date&#xff1a;2025年1月22日 漫漫长路有人对你微笑过嘛… 全系列文章可查看专栏: Linux实践记录_Once_day的博客-CSDN博客 参考文档&#xff1a; ARM Trusted Firmware分析——启动、PSCI、OP-TEE接口 Arnold Lu 博…

解决docker: ‘buildx‘ is not a docker command.

简介 buildx 是 Docker 官方提供的一个构建工具&#xff0c;它可以帮助用户快速、高效地构建 Docker 镜像&#xff0c;并支持多种平台的构建。使用 buildx&#xff0c;用户可以在单个命令中构建多种架构的镜像&#xff0c;例如 x86 和 ARM 架构&#xff0c;而无需手动操作多个…

提示词工程(Prompt Engineering)

1. Prompt 是什么&#xff1f; Prompt&#xff1a;提示词&#xff0c;是描述 AI 需要执行的任务的自然语言文本。 如上图所示&#xff0c;Prompt就是用户的提问。其实我们大家都用过Prompt&#xff0c;比如我们使用的ChatGPT、文心一言、豆包等AI产品时的提问就是Prompt&…

【Linux】文件操作、系统IO相关操作、inode和输入输出重定向

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、理解文件1.1 狭义理解1.2 广义理解1.3 文件操作1.4 系统角度 2、系统文件IO2.1 文件相关操作2.2 文件描述符2.3 重定向 3、动静…

头像生成小程序搭建(免费分享)

如下图为小程序页面的基本效果&#xff0c;下面将介绍该小程序的功能 页面template代码如下&#xff1a; <template><view class"avatar-containner"><block v-if"!showCropper"><image class"pageback" src"../../s…

2025寒假备战蓝桥杯02---朴素二分查找升级版本的学习+分别求解左右端点

文章目录 1.朴素二分查找的升级版2.查找左端点3.查找右端点4.代码的编写 1.朴素二分查找的升级版 和之前介绍的这个二分查找相比&#xff0c;我觉得这个区别就是我们的这个二分查找需要找到的是一个区间&#xff0c;而不是这个区间里面的某一个元素的位置&#xff1b; 2.查找…

css命名规范——BEM

目录 引言 BEM是什么? 块Block 元素Element 修饰语Modifier BEM解决了哪些问题? 在流行框架的组件中使用 BEM 格式 实战 认识设计图 如何使用当前的css规范正确命名? 引言 css样式类命名难、太难了,难于上青天,这个和js变量命名还不一样。看看项目中五花八门的样…

C++AVL树(一)详解

文章目录 AVL树概念AVL树的插入平衡因子的更新旋转的规则左单旋右单旋抽象的情况h0h1h 2h 3 AVL树 概念 AVL树是一棵平衡二叉查找树&#xff0c;AVL树是空树&#xff0c;保证左右子树都是AVL树&#xff0c;AVL树要求高度差的绝对值不超过1&#xff0c;因为最好情况是1&#…