备赛·双指针

这是我看了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;
	
}

 这样会超时,时间复杂度为O(n^{4})

下面是快慢指针做法

#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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值