概念分析:双指针
(包含同向指针,也就是快慢指针,经典例题应用是回文字符串
还有反向指针,也叫左右指针)
且这类题目往往和排序联系在一起!!!
本质:就是将二维的转化为一维的,但是并不是所有的题目都可以转化
//举个例子
//二维代码
for(int i=0;i<n;i++){
for(int j=n-1;j>=0;j--){
………………
}
}
//一维代码
for(int i=0,j=n-1;i<j;i++,j--){
…………
}
一、较为容易的题目
1.回文串的判断-->同向指针
//关键代码 int main(){ string x; cin>>x; int ret=1; int x1=x.size() ;//字符串的长度 for(int i=0;i<x1;i++){ if(x[i]!=x[x1-1-i]){ ret=0; break; } } }
2.寻找区间和
int main(){
string x;
int s;
cin>>x>>s;
int x1=x.size() ;
int i=0,j=0,sum=x[0]-'0';
while(j<x1){
if(sum>=s){//从暴力的O(n^2)的时间复杂度变成O(n)
if(sum==s) cout<<i<<' '<<j<<endl;
sum-=x[i]-'0';
i++;
}
if(i>j){//这一步要小心哦,因为要保证i在j的后面哦
sum=x[i]-'0';
j++;
}
if(sum<s){
j++;
sum+=x[j]-'0';
}
}
return 0;
}
二、加大难度的题目
1.日志统计(其实也就多了个数组的标记)
//根据题目数据范围知道必须是O(n)的才能过
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int NUM=1e5+5;
struct post{
int ts;
int id;
};
bool pp[NUM];
post pt[NUM];
int num[NUM];//用来记录每一个id的出现次数
int cmp(post &a,post &b){
return a.ts <b.ts ;//从小到大
}
int main(){
int n,k,d;
cin>>n>>d>>k;
for(int i=0;i<n;i++) scanf("%d %d",&pt[i].ts ,&pt[i].id );
//先排序
sort(pt,pt+n,cmp);
// //调试一下
// for(int i=0;i<n;i++) cout<<pt[i].ts<<' '<<pt[i].id <<endl;
int i=0,j=0;
while(j<n){
while(pt[j].ts<pt[i].ts +d&&j<n){
num[pt[j].id ]++;
if(num[pt[j].id ]>=k&&!pp[pt[j].id ]) {
cout<<pt[j].id <<endl;
pp[pt[j].id ]=true;
}
j++;
}
num[pt[i].id]--;
i++;
}
return 0;
}
2.锻造兵器
此题就难在有重复的,那么又该怎么解决?
将双指针进化吧!进化成三指针!(这也告诉我们做题时不要只局限于算法的名字,而是应该根据算法的原理去灵活运用)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int NUM=1e5;
int ai[NUM];
int cmp(int a,int b){
return a<b;//从小到大
}
int main(){
int n,c;
cin>>n>>c;
for(int i=0;i<n;i++) cin>>ai[i];
//同时也先排序吧!
sort(ai,ai+n,cmp);
int sum=0;
for(int i=0,j=0,k=0;i<n;i++){
//i是主指针
while(ai[j]-ai[i]<c) j++;//目的是形成一个区间窗口。 -->妙啊!
while(ai[k]-ai[i]<=c) k++;
sum+=k-j-1;
}
cout<<sum<<endl;
return 0;
}