一、双指针算法
1、运用某些性质 O(n^2)->O(n)
(一)将一段字符串的单词逐行输出
#include<bits/stdc++.h>
//找单词输出(默认开头没有空格,并单词之间只有一个空格)
using namespace std;
const int N=1e3+10;
int n;
int main()
{
char s[N];
gets(s);//字符串的输入方式
n=strlen(s);
for(int i=0;i<n;i++)
{
int j=i;
while(j<n&&s[j]!=' ')j++;
for(int k=i;k<j;k++)cout<<s[k];
cout<<endl;
i=j;//每个循环加加
}
}
(二)求一个字符串的最长连续不重复子序列的长度
i作为子序列末尾进行枚举,每次找最左的j的位置。j不可能向前走,因为j向后走的原因就是这个子序列里面已经有重复元素了。
#include<bits/stdc++.h>
//799
using namespace std;
const int N=1e3+10;
int a[N];
int s[N];//用于保证当前的子序列中没有重复元素
int n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
int res=0;
for(int i=0,j=0;i<n;i++)
{
s[a[i]]++;
while(s[a[i]]>1)//只要出现重复元素,调整j,从左向右依次剖出元素
{
s[a[j]]--;
j++;
}
res=max(res,i-j+1);
}
cout<<res<<endl;
return 0;
}
二、二进制
(三)看某一个数字的二进制的第k位是什么
#include<bits/stdc++.h>
//看某一个数字的二进制的第k位是什么
using namespace std;
const int N=1e3+10;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
cout<<(n>>k&1);
}
1、lowbit(x)返回最后一位1
计算方式:x&-x即可得到
(四)应用:统计1的个数
#include<bits/stdc++.h>
//801 求给定数字的1的个数
using namespace std;
const int N=1e3+10;
int lowbit(int x)
{
return x & -x;
}
int main()
{
int n;
cin>>n;
while(n--)
{
int x;
cin>>x;
int res=0;
while(x)x-=lowbit(x),res++;
cout<<res<<endl;
}
}
三、离散化求区间和
1、值域跨度很大,很稀疏
#include<bits/stdc++.h>
//802 区间和
using namespace std;
const int N=3e5+10;
typedef pair<int,int>PII;
int n,m;
int a[N],s[N];
vector<int>alls;//所有下标和询问所需要的下标
vector<PII>add,query;//存储所有插入和询问
int find(int 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+1;//因为得到位置之后要在a上加加,又因为后面要求前缀和,所以得到的下标又加一
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
int x,c;
cin>>x>>c;
add.push_back({x,c});//保存插入的位置和数据
alls.push_back(x);//保存插入的位置
}
for(int i=0;i<m;i++)
{
int l,r;
cin>>l>>r;
query.push_back({l,r});//保存询问
alls.push_back(l);//保存询问下标,all里存储的是全部要用的下标
alls.push_back(r);
}
//去重
sort(alls.begin(),alls.end());//由于下标很稀疏,先进行排序
alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重
//添加数字的时候
for(auto item :add)
{
int x=find(item.first);
a[x]+=item.second;
}
for(int i=1;i<=alls.size();i++)s[i]=s[i-1]+a[i];
for (auto item:query)
{
int l=find(item.first),r=find(item.second);
cout<<s[r]-s[l-1]<<endl;
}
}
2、unique的实现:获取数组的所有不重复的元素
vecotr<int>::iterator unique(vector<int> a)
{
int j=0;
for(int i=0;i<a.size();i++)
if(!i||a[i]!=a[i-1])
a[j++]=a[i];
return a.begin()+j;
}
四、区间合并
1、输入n个区间进行合并,得到最后的区间个数
#include<bits/stdc++.h>
//803 区间合并
using namespace std;
const int N=1e5+10;
typedef pair<int,int>PII;
int n;
void merge(vector<PII>segs)
{
sort(segs.begin(),segs.end());
int st=-2e9,ed=-2e9;//存
vector<PII>res;
for(auto item:segs)
{
if(item.first>ed)//比较
{
if(st!=-2e9)res.push_back({st,ed});
st=item.first,ed=item.second;
}
else ed=max(ed,item.second);
}
if(st!=-2e9)res.push_back({st,ed});//不要落下最后一个
segs=res;
}
vector<PII>segs;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
segs.push_back({l,r});
}
merge(segs);
cout<<segs.size()<<endl;
}