3768. 字符串删减
while循环的双指针,只要遇到一个x,就让y向前探索。不是就加加。
cpp
#include<bits/stdc++.h>
using namespace std;
//3768. 字符串删减
char s[110];
int n;
int cnt=0;
int sum=0;
int main()
{
cin>>n;
cin>>s;
int x=0,y=0;
while(y<n)
{
if(s[x]=='x')
{
y=x;
cnt=0;
while(y<n&&s[y]=='x')
{
cnt++;
y++;
}
if(cnt>=3)sum+=(cnt-2);
x=y+1;
}
else
{
x++,y=x;
}
}
cout<<sum<<endl;
}
799 最长连续不重复子序列
使用set存储,最初的时候,每次更新ans都是用set的size-1,但是这落下了一种情况,while结束的条件一种是y遇到了set中重复的数,一种是y到头了,所以用y-x去更新值。
cpp
#include<bits/stdc++.h>
using namespace std;
//799 最长连续不重复子序列
const int N=1e5+10;
int a[N];
int n;
int ans=1;
unordered_set<int> se;
int main()
{
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
int x=0,y=0;
while(y<n)
{
//无y
if(!se.count(a[y]))
{
while(!se.count(a[y])&&y<n)
{
se.insert(a[y++]);
}
ans=max(ans,y-x);
}
//有y
else
{
while(se.count(a[y]))
{
se.erase(a[x++]);
}
}
}
cout<<ans<<endl;
}
800 数组元素的目标和
能用双指针不仅仅是求最长序列这种情况。
本质应该是利用数据本身的特点用双指针实现一些不必要的迭代。
最开始也想到了利用有序这个特点,但是没想出来。'
cpp
#include<bits/stdc++.h>
using namespace std;
//800 数组元素的目标和
const int N=1e5+10;
int a[N],b[N];
int n,m,x;
int main()
{
cin>>n>>m>>x;
for(int i=0;i<n;i++)cin>>a[i];
for(int j=0;j<m;j++)cin>>b[j];
//类似剪枝
for(int i=0,j=m-1;i<n;i++)
{
while(b[j]+a[i]>x&&j>=0)
{
j--;
}
if(b[j]+a[i]==x)
{
cout<<i<<" "<<j<<endl;
return 0;
}
}
}
2816. 判断子序列
开始输入写错了
cpp
#include<bits/stdc++.h>
using namespace std;
//2816 判断子序列
const int N=1e5+10;
int a[N],b[N];
int n,m,x;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
for(int j=0;j<m;j++)cin>>b[j];
//判断a是否是b的子序列
int i=0,j=0;
while(j<m)
{
//匹配ij都往后走,
if(b[j]==a[i])
{
j++,i++;
if(i==n)
{
cout<<"Yes";
return 0;
}
}
else
{
j++;
}
//到头了
}
//如果是因为j到头了
if(j==m)
puts("No");
}
1238日志统计
只要存在某个固定长度的子串某个id的点赞数超过某个数,就是热门。
最初的做法是只是 找了所有不重合区间的情况。少了很多情况。
可以存储多个元素的set : multiset
当你需要删除某个数(不重复删除)
cpp
auto it=se.find(rang[i].id);
se.erase(it);
cpp
#include<bits/stdc++.h>
using namespace std;
//1238 日志统计(超时做法)
const int N=1e5+10;
int n,d,k;
multiset<int>se;//存某个区间某个id出现的次数
map<int,int> mp;//存在几个区间符合要求
struct Range
{
int ts,id;
bool operator<(const Range &W)
{
return ts<W.ts;
}
}rang[N];
int main()
{
cin>>n>>d>>k;
for(int i=0;i<n;i++)
{
int t,id;
cin>>t>>id;
rang[i]={t,id};
}
sort(rang,rang+n);
int i=0,j=0;
while(i<n)
{
//走一个区间
while(rang[j].ts<rang[i].ts+d&&j<n)
{
//记录走到的某个点赞记录
int t=rang[j].id;
j++;
se.insert(t);
//如果符合条件
if(se.count(t)>=k)
{
mp[t]++;
}
}
//i向前走一步,i号记录在set中的id要减少一个
auto it=se.find(rang[i].id);
se.erase(it);
i++;
}
for(auto t=mp.begin();t!=mp.end();t++)
{
if(t->second)
cout<<t->first<<endl;
}
}
y做法:直接用cnt数组动态存储区间中id的个数,只要j离i太远了,就去减去。
1240 完全二叉树的权值
最初自己的做法是从第二行开始判断,也就是i从1开始遍历,i*2只要没越界就用j从i*2+1开始遍历。一个点老是过不了。
最后采用y做法,从第一行开始遍历,j< i+(1 < <(lay -1))为边界
cpp
#include<bits/stdc++.h>
using namespace std;
//1240 完全二叉树的权值
const int N=1e5+10,INF=1e18+10;
int n;
int a[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
long long m=-1*INF,idx,lay=1;
for(int i=1;i<=n;i*=2)
{
long long sum=0;
int j=i;
while(j<i+(1<<lay-1)&&j<=n)
{
sum+=a[j];
j++;
}
if(sum>m)
{
m=sum;
idx=lay;
}
lay++;
}
cout<<idx<<endl;
}