Date:2022.04.02
题意描述:
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:
ts id
表示在 ts 时刻编号 id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数 N,D,K。
以下 N 行每行一条日志,包含两个整数 ts 和 id。
输出格式
按从小到大的顺序输出热帖 id。
每个 id 占一行。
数据范围
1≤K≤N≤105,
0≤ts,id≤105,
1≤D≤10000
输入样例:
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出样例:
1
3
思路①:O(N2)O(N^2)O(N2)
枚举每一个时间点ttt,看[t,t+d)[t,t+d)[t,t+d)范围内所有ididid有哪些出现了>=k>=k>=k次的即为热帖。由于每次要枚举所有ididid并统计所有ididid的数量,所以每次要memsetmemsetmemset一下ididid。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL sum[N],cnt[N],n,k,d,a[N],b[N];
bool st[N];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>d>>k;LL maxt=0,maxid=0;
for(int i=1;i<=n;i++)
{
cin>>zan[i].ts>>zan[i].id;
maxt=max(maxt,zan[i].ts);
}
for(int t=0;t<=maxt;t++)
{
memset(cnt,0,sizeof cnt);
for(int i=1;i<=n;i++)
{
LL id=zan[i].id;
if(zan[i].ts>=t&&zan[i].ts<t+d) cnt[id]++;
if(cnt[id]>=k) {st[id]=true;continue;}
}
}
LL ans=0;
for(int i=0;i<N;i++)
if(st[i]) cout<<i<<'\n';
return 0;
}
思路②:O(N)O(N)O(N)。
暴力的瓶颈有两个:
1.枚举的是所有时间,若数据按tststs排序后是多个1、100000显然枚举所有时间不明智。(当然如果硬说,这个算是软优化)
2.每次都要统计所有ididid在这个时间段的出现次数,所以每次要枚举nnn个数也要memsetmemsetmemset一下,复杂度自然多一维。
我们将所有点赞按时间为第一关键字排序,这样我们可以用双指针每次来动态维护一个时间在[t,t+d)[t,t+d)[t,t+d)内的区间,但是双指针的i、ji、ji、j是所有赞的编号。这样一来,每次后面的j++j++j++,而且对应的cnt[zan[j].id]++cnt[zan[j].id]++cnt[zan[j].id]++,并且每次将时间的右界变为zan[j].tszan[j].tszan[j].ts,由此左边iii对应的zan[i].tszan[i].tszan[i].ts如果不满足zan[j].ts−zan[i].ts<dzan[j].ts-zan[i].ts<dzan[j].ts−zan[i].ts<d那就不要它了,对应的cnt[zan[i].id]−−cnt[zan[i].id]--cnt[zan[i].id]−−,之后i++i++i++。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
typedef long long LL;
LL cnt[N],n,m,t,k,d;
bool st[N];
struct node
{
LL ts,id;
bool operator<(const node&t)const
{
if(ts!=t.ts) return ts<t.ts;
return id<t.id;
}
}zan[N];
int main()
{
cin>>n>>d>>k;
for(int i=1;i<=n;i++)
cin>>zan[i].ts>>zan[i].id;
sort(zan+1,zan+1+n);
LL i,j;
for(i=1,j=1;i<=n;)
{
cnt[zan[i].id]++;
while(zan[i].ts-zan[j].ts>=d)
{
cnt[zan[j].id]--;
j++;
}
if(cnt[zan[i].id]>=k) st[zan[i].id]=true;
i++;//放最后
}
for(int i=0;i<N;i++)
if(st[i]) cout<<i<<'\n';
return 0;
}
这篇博客介绍了如何使用双指针优化算法,将时间复杂度从O(N^2)降低到O(N),以解决在给定时间段内统计帖子点赞数量判断热帖的问题。博主详细阐述了两种解决方案,一种是暴力枚举时间点,另一种是通过对点赞日志排序并使用双指针动态维护区间,从而高效地找出热帖。这两种方法在处理大量数据时效率差异显著,优化后的算法大大提高了处理速度。
1万+

被折叠的 条评论
为什么被折叠?



