这是我看了B站up主一只会code的小金鱼的视频的学习笔记
通过做题来理解双指针
不考虑时间性能
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int q[N];
bool check(int left, int right) {
for (int i = left; i <= right; i++) {
for (int j = i; j <= right; j++) {
if (i != j && q[i] == q[j]) return false;
}
}
return true;
}
int main() {
scanf("%d", &n);//输入子序列的个数
for (int i = 1; i <= n; i++)
scanf("%d", &q[i]);
int res = 1;
for (int i = 1; i <= n; i++) {
for (int j = i+1; j <= n; j++) {
if (check(i, j)) {
res = max(res,j - i + 1);
}
}
}
printf("%d\n", res);
return 0;
}
这样会超时,时间复杂度为
下面是快慢指针做法
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
int q[N];
int cnt[N];//记录每个数字出现的次数
bool check(int left, int right) {
for (int i = left; i <= right; i++) {
for (int j = i; j <= right; j++) {
if (i != j && q[i] == q[j]) return false;
}
}
return true;
}
int main() {
scanf("%d", &n);//输入子序列的个数
for (int i = 1; i <= n; i++)
scanf("%d", &q[i]);
int res = 1;
for (int i = 1,j=1; i <=n; i++) {
cnt[q[i]]++;
while (cnt[q[i]] > 1) {
cnt[q[j]]--;
j++;//运用j指针把前面的数据清空
}
res = max(res, i - j + 1);
}
printf("%d\n", res);
return 0;
}
下面是画图步骤理解
对撞指针:如快速排序
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
//快速排序算法
//顺序表
#define MaxSize 100
typedef int ElemType;
typedef struct {
ElemType* elem;
int length;
}SqList;
//初始化
bool initList(SqList& L) {
L.elem = new int[MaxSize];
if (!L.elem) return false;
L.length = 0;
return true;
}
//输入数据
void Input(SqList& L, int n) {
if (n > MaxSize) {
cout << "太多了,放不下" << endl;
return;
}
cout << "请输入数据:";
for (int i = 1; i <= n; i++) {
cin >> L.elem[i];
}
L.length = n;
}
//分区算法
int Partition(SqList& L, int low, int high) {
//对排序区间L.R[low..high]进行一次分区,返回基准位置下标
int pivotkey = L.elem[low]; int i = low; int j = high; L.elem[0] = L.elem[low];
while (i < j) {
while (j > i && L.elem[j] >= pivotkey) j--; //i指向基准,j向右扫描
L.elem[i] = L.elem[j]; // 比基准小的记录左移
while (i < j && L.elem[i] <= pivotkey) i++; //j指向基准i向左扫描
L.elem[j] = L.elem[i]; // 比基准大的记录右移
}
L.elem[i] = L.elem[0]; //基准到位
return i; //返回基准的位置下标
}
//对[low,high]区间的快速排序算法
void QSort(SqList& L, int low, int high) {
//对排序区间L.R[low..high]进行快速排序
if (low < high) {
int pivotloc = Partition(L, low, high); //进行分区,返回基准下标
QSort(L, low, pivotloc - 1); // 对左半区进行快速排序
QSort(L, pivotloc + 1, high); // 对右半区进行快速排序
}
}
//对整个顺序表
void QuickSort(SqList& L) {
// 对整个顺序表进行快速排序
QSort(L, 1, L.length);
}
// 打印顺序表
void PrintList(SqList L) {
for (int i = 1; i <= L.length; i++) {
cout << L.elem[i] << " ";
}
cout << endl;
}
int main() {
SqList L;
if (!initList(L)) {
cout << "初始化失败!" << endl;
return 1;
}
int n;
cout << "请输入要排序的元素个数:";
cin >> n;
Input(L, n);
cout << "排序前的顺序表:" << endl;
PrintList(L);
QuickSort(L);
cout << "排序后的顺序表:" << endl;
PrintList(L);
// 释放内存
delete[] L.elem;
return 0;
}
双指针:暴力优化
通用模板:
for(int i=1,j=1;i<=n;i++){
while( j < i && check(i,j)){
j++;
}
}
前缀和 ----- 数组前n项和
作用:快速求出数组中一段区间和。
int a[N];
S[n] = a[1] + a[2] + ... + a[n-1] + a[n];
一维前缀和
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =100010;
int n,m;
int a[N];
int sum[N];//前缀和数组
int main(){
//一般的求区间和的做法(易超时)
/*scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
while(m--){
int l,r;
scanf("%d %d",&l,&r);
int sum=0;
for(int i=l;i<=r;i++){
sum += a[i];
}
printf("%d\n",sum);
}*/
//前缀和
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
}
while(m--){
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",sum[r]-sum[j-1]);
}
return 0;
}
二维前缀和
#include<iostream>
#inlcude<cstring>
$include<algorithm>
using namespace std;
const int N = 1010;
int n,m,k;
int q[N][N], s[N][N];
int main(){
cin>>n>>m>>k;
for(int i =1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&q[i][j]);
s[i][j] = q[i][j] + s[i-1][j] + s[i][j-1] -s[i-1][j-1];
}
}
while(k--){
int x1,y1,x2,y2;
scnaf("%d %d %d %d",&x1,&y1,&x2,&y2);
printf("%d\n",s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1-1][y1-1] );
}
return 0;
}
程序中
关于前缀和的一个例题
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;//能表示更大的整数范围。
const int N =500010;
int n;
LL s[N];
int main(){
int T;//T个独立的测试用例。
scanf("%d",&T);
while(T--){
scanf("%d",&n);//几个蛋糕数
LL a = 1e15;//Smin
int l = n/2+1;
//预处理一下前缀和
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
s[i]=s[i-1]+x;
if(i>=l) a = min(a,s[i]-s[i-l]);
}
printf("%lld %lld\n",a,s[n]-a);
}
return 0;
}