双指针算法。
相向双指针,指的是在算法的一开始,两根指针分别位于数组/字符串的两端,并相向行走。
ACWING 的一道裸题(不知道为啥进不去404):最长连续不重复子序列
输入
5
1 2 2 3 5
输出
3
需要两个指针,指针范围为不重复自序列,i,j为其两端。j为左边,i为右边。a【】数组记录原数组,s【】数组记录数字出现次数。怎么搞呢,举个例子,对于样例1 :
1 2 2 3 5
0 1 2 3 4
首先j=0,i=0。。如果当前没有出现某个数的出现次数>1,那么i++,j不变。当 j=0,i=2时,出现了s[2]>1,2出现了2次,很明显不符题意了。那么需要移动指针了。根据常识,我们需要从当前出现两次的数重新开始计了,即 从i=2,j=2开始,我们可以看到,i没变,j移动了,总结:出现次数大于1的数,i不变,j右移,直到i==j。但是既然要重新计,那么记录次数的s[]数组肯定要清一下,所以s[a[j]]--,在j右移的过程中逐步清掉s[]数组,由于出了s[i]==2以外s[j]==1,所以可以把他们都清为s[a[j]]==0,而顺便把重复数s[a[ i ]]==1,重新开始计。
有点啰嗦了,代码:
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1e5; int a[maxn],s[maxn]; int main() { int n; cin>>n; for(int i = 0 ;i < n ;i++) cin>>a[i]; int maxx=-1 ; for(int i= 0 ,j=0;i< n;i++) { s[a[i]]++; while(s[a[i]]>1) { s[a[j]]--; j++; } maxx=max(i-j+1,maxx); } cout<<maxx<<endl; }
给定两个升序排序的有序数组A和B,以及一个目标值x。数组下标从0开始。请你求出满足A[i] + B[j] = x的数对(i, j)。
本来写了一个双指针,结果超时了,j每次清0的操作实在花了好多无用功。因为题目中给的两个数组,均为升序排列。所以,用 i 代表a[]数组,j 为b[]数组。j从右往左滑,i往右划。
由于是升序排列,所以j并不需要清成m-1,因为比如:i 在 1位置+j在2位置 ==x,那么下一次 i 右移,j不会再往右移,如果往右移接下来的a+b一定>x,没必要再算了。j不能从左往右滑,不再解释,还是因为升序数组。
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1e5+10; int a[maxn],b[maxn];// int main() { int n ,m ,x; cin>>n>>m>>x; for(int i= 0 ;i < n ; i++) cin>>a[i]; for(int i = 0 ;i< m; i++) cin>>b[i]; int ans=0; for(int i = 0 ,j = m-1 ; i < n && j>=0; i++) { while(a[i]+b[j]>x&&j>=0) { j--; } if(a[i]+b[j]==x) cout<<i<<" "<<j<<endl; } }
位运算 :
1: n的二进制表示中第k位是几? n > > k & 1
模板:表示N的二进制
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1e5+10; int a[maxn],b[maxn];// int main() { int n; while(cin>>n) { for(int k=9 ;k>=0; k-- ) cout<<(n>>k&1); cout<<endl; } }
2: 返回x(二进制)的最后一位1的位置
x & (-x)==x & (x取反+1)
二进制中1的个数
#include<iostream> #include<cstdio> using namespace std; const int maxn = 1e5+10; int a[maxn],b[maxn];// int lowbit(int a) { return a&(-a); } int main() { int n; cin>>n; for(int i=1;i<=n;i++) { int x; int ans=0; cin>>x; while(x) { ans++; x-=lowbit(x); //每次减去x的最后一位 } cout<<ans<<' '; } }
离散化:整数离散化:
要点: 1:重复元素的去重。2:如何算离散化值
//排序加去重
void quchong() { vector<int>alls; //存储所有待离散化的值 sort(alls.begin(),alls.end()); //将所有值排序 alls.erase(unique(alls.begin(),alls.end()),alls.end()); //去掉重复元素 }
//二分法求出x对应的离散化的值 int find(int x) //找到第一个大于等于x的位置 { int l = 0 , r= alls.size()-1; while(l<r) { int mid=(l+r)>>1; if(alls[mid]>=x) r=mid; else l=mid+1; } return r; //映射 }
ACWING 区间和
10^9,不能用前缀和了。分析一下,n+2*m个坐标==3*10^5,用得着的也就这么些坐标了,其他的没必要看,所以可以用离散化来做。
ACWING 区间合并
vector的不会做,自己写的代码
#include<iostream> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int maxn = 1e5+10; struct node { int l,r; }st[maxn]; bool cmp(node a,node b) { return a.l<b.l; } int main() { int n ; cin>>n; for(int i= 0 ; i < n; i++) { cin>>st[i].l>>st[i].r; } sort(st,st+n,cmp); int sum = 1 ; for(int i= 0;i < n ;i++) { if(st[i].r<st[i+1].l) { sum++; // cout<<st[i].l<<" "<<st[i].r<<" -"<<st[i+1].l<<" "<<st[i+1].r<<endl; } else { if(st[i].r>st[i+1].r) { st[i+1].r=st[i].r; } } } cout<<sum<<endl; }