two-pointer 双指针法—初步介绍

例题1:给出n个数,找出和最接近k的两个数。

思路 :对数组进行排序,一个指针指向1(最小),另一个指向n(最大)。如果两指针之和大于k,则右指针左移1;如果两指针之和小于k,则左指针右移1。

其中左移意为使值变大,右移意为使值变小,两两交换移动,就能最大可能的接近k。


例题2:给出n个数,找出和最接近k的三个数。

思路 :枚举1个数,其余与例题1一致。注意对于nums[st],nums[ed]和nums[i],都要判断是不是与前一个数相等。


例题3:给出n个数,问最多能组成多少个三角形。

思路 :枚举b(第2边),一个指针指向a,另一个指向c,如果满足a+b>c就是一个三角形,同时得知 b后面的数+c>a一定成立,然后end--。如果b+c


例题4:给你一个长度为n的序列,对于所有长度>=k的选出其中的第k小元素,于是得到一个新的集合,求出这个集合中的第l大元素,数据范围n<=100000,所有数<=1e8。

思路 :考虑二分答案,对于当前答案x,如果至少包含k个小于等于x的区间的数量

对于当前答案x, 我们对于原数列的每个数如果>x 那么赋值为0,否则为1。于是我们只需要计算和大于等于k的区间数就可以了,这个显然是可以用two-pointer在O(n)时间内完成的。


代码:

#include 
#define Maxn 2000007
using namespace std;
int n,k;
long long l;
int a[Maxn],b[Maxn];
long long tryit(int x)//计算和大于等于k的区间数
{
	for (int i=1;i<=n;i++)
		if (a[i]>x) b[i]=0;
		else b[i]=1;
	long long ans=0;
	int now=1,r=b[1];//now是右指针,r是累计大于x的数的个数
	for (int i=1;i<=n;i++)
	{
		while (now<=n&&r1)
	{
		int mid=(lx+rx)/2;
		if (tryit(mid)>=1LL*(n-k+1)*(n-k+2)/2-l) rx=mid; else lx=mid;
	}
	if (tryit(rx)>=1LL*(n-k+1)*(n-k+2)/2-l) printf("%d\n",rx); else printf("%d\n",lx);
	return 0;
}


你可能感兴趣的:(双指针)