双指针算法:
例题1.最长连续不重复子序列:
给定一个长度为 n 的整数序列q,请找出最长的不包含重复的数的连续区间。
数据范围:
1<=n<=1e5;
1<=q[i]<=1e5。
思路:
枚举所有区间,c(n,2),时间复杂度为O(n^2);
使用双指针算法,先固定一个左端点i,然后另一个端点j向前扫描;
当遇到重复的数后,将i向前移动到区间内不存在重复数的位置,然后重复上述操作即可;
(当i移动完成停下后,说明q[i-1]==q[j],所以q[j]不可能与q[i]之前的数形成不重复区间);
时间复杂度为O(n)。
代码如下:
int i=0,j=0;//左右指针
st[q[i]]++;//q[i]的数量+1
while(j<n){
//如果重复就将i往前移
while(st[q[j]]==2){
st[q[i]]--;
i++;
}
res=max(res,j-i+1);
j++;
st[q[j]]++;
}
例题2.数组元素的目标和:
给定两个升序排列的序列p,q,以及一个目标值x,求满足p[i]+q[j]==x的一组(i,j)。数据保证有解并且唯一解。
数据范围:
1<=p,q<=1e5;
1<=p[i],q[i]<=1e9。
思路:
指针i指向p的首项,j指向q的尾项;
如果p[i]+q[j]>x,则向前移动j,如果p[i]+p[j]<x,则向后移动i;
(当p[i]+q[j]>x时,q[j]~q[n]不可能与p[i]~q[n]组成x,所以可以舍弃掉q[j],另一种情况同理)。
代码如下:
for(int i=0,j=m-1;i<n&&j>=0;){
if(a[i]+b[j]>t)j--;
else if(a[i]+b[j]<t)i++;
else if(a[i]+b[j]==t){cout<<i<<" "<<j;return 0;}
}
例题3.盛水最多的容器
给定一个整数序列,每个数都代表一个挡板,每个相邻的挡板间的距离都是1,数的大小代表挡板的高度。
找出其中的两个挡板,使得他们与x轴共同构成的容器可以容纳最多的水。
你不都倾斜容器。
思路:
假设挡板i,j,挡板高度h[i],可以把盛水的量s看作是q[j]-q[i]*max(h[i],h[j]);
初始状态i,j置于两侧;
不论移动哪一个挡板,q[j]-q[i]都会变小,要想结果可能变大,必须要尽可能使得max(h[i],h[j])变大,所以我们每次移动较矮的挡板。
代码如下:
for (int i = 0, j = height.size() - 1; i < j;) {
res = max(res, min(height[i], height[j]) * (j - i));
if (height[i] < height[j])i++;
else j--;
}