- 第 88 篇 -
Date: 2025 - 04 - 06(发博客时间)
Author: 郑龙浩/仟墨
【双指针与前缀和 C/C++】
双指针与前缀和
记笔记时间: 2025-04-02
文章目录
- 双指针与前缀和
-
- [1 基本介绍](#1 基本介绍)
- [2 双指针 - 例题](#2 双指针 - 例题)
- [蓝桥杯第15届C/C++B组省赛 H题 - 拔河](#蓝桥杯第15届C/C++B组省赛 H题 - 拔河)
1 基本介绍
准确来说,双指针只能说是算法中的一个技巧。
它并没有一个固定的模板,只是一个思想
双指针在遍历数据的过程当中不是简单的使用单个指针进行访问(也就是不是遍历一遍),而是使用两个相同方向或者相反方向的指针进行扫描。
双指针也可和前缀和结合使用
两种
-
最常见
在一个序列里边, 用两个指针维护一段区间
-
不常见
在两个序列里边,一个指针指向其中一个序列,另一个指针指向另一个序列,来维护某种次序。
核心思想
当暴力过不了的时候,可以使用双指针进行优化
2 双指针 - 例题
将两个有序顺序表合并成一个新的有序顺序表,并由函数返回结果顺序表
cpp
[38, 49, 65, 97] [13, 27, 76]
代码
cpp
// 将两个有序顺序表合并成一个新的有序顺序表,并由函数返回结果顺序表
// ```cpp
// [38, 49, 65, 97] [13, 27, 76]
// ```
#include <bits/stdc++.h>
using namespace std;
const int N = 4;
const int M = 3;
int arr[N] = {38, 49, 65, 97}, arr2[M] = {13, 27, 76}, ans[N + M];
int k = 0; // ans的长度
int main( void ) {
int i = 0, j = 0;
while (i < N && j < M) {
if (arr[i] < arr2[j]) ans[k ++] = arr[i ++];
else ans[k ++] = arr2[j ++];
}
// 为什么还要再写两遍while呢
// 因为会出现两种情况
// 1 当arr2数组全部放到ans数组中时,arr2数组中的数没完全或者没有放到ans数组中,所以需要二次遍历
// 2 当arr数组全部放到ans数组中时,arr数组中的数没完全或者没有放到ans数组中,所以需要二次遍历
// i < N 意思是 arr 数组中还有数值没有被遍历
// j == M 意思是 arr2 数值中的数值已经全部被遍历,因为只有全部被遍历之后才会指向M
while (i < N && j == M) ans[k ++] = arr[i ++]; //j == m 写不写都行,主要是便于理解的
while (j < M && i == N) ans[k ++] = arr2[j ++]; //i == N 写不写都行
for (int i = 0; i < N + M; i ++) {
cout << ans[i] << ' ';
}
return 0;
}
蓝桥杯第15届C/C++B组省赛 H题 - 拔河
cpp
// 试题H 洛谷P10429 拔河 第二次写
// Date: 2025-04-04
// Author: 郑龙浩 / 仟墨
// 算法: 双指针 + 前缀和
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e3 + 5;
int n;// 人数
ll arr[N], sumA = 0, sumB = 0, minNum = LLONG_MAX;
int main( void ) {
cin >> n;
for (int i = 0; i < n; i ++) cin >> arr[i];
for (int i = 0; i < n - 1; i ++) {
for (int j = i + 1; j < n; j ++) {
sumA = arr[i], sumB = arr[j]; // 重置总和
minNum = min(minNum, abs(sumB - sumA));
int l = i - 1, r = j + 1; // 左右
while (l >= 0 && r < n) { // 若指针指向的是队伍内
if (sumA < sumB) {
sumA += arr[l];
l --;
minNum = min(minNum, abs(sumB - sumA));
} else {
sumB += arr[r];
r ++;
minNum = min(minNum, abs(sumB - sumA));
}
}
while (l >= 0 && r == n) {
sumA += arr[l];
l --;
minNum = min(minNum, abs(sumB - sumA));
}
while (r < n && l == 0) {
sumB += arr[r];
r ++;
minNum = min(minNum, abs(sumB - sumA));
}
}
}
cout << minNum << '\n';
return 0;
}