1.定义:
双指针算法是一个用来优化操作的思想,可以降低代码的时间复杂度
例题:日志统计
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 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
解题思路:
(1)暴力枚举:枚举在每个规定的时间段内,每个帖子的点赞次数,判断是否达到要求(每个新的时间段内需要重置计数的数组)。此时的时间复杂度会超时,用双指针来优化中间代码
伪代码:
优化方式:每个时间段内只有开头和结尾不一样,中间内容是重复的,因此可以在下一个时间段中,减去i时间的点赞数量并且加上j时间的点赞数量(每次操作i,j两个下标,即为双指针算法)
优化后的伪代码:
二元组的使用:
当每次需要存入两个数字时可以使用二元组或结构体
二元组:
假设定义的二元组名字为p,则获取p的第一个值,写法:p[i].first,获取第二值写法:p[i].second
用x,y代替可以简化代码
二元组的排序默认是以第一个元素进行排序,第一个元素相同则按照第二个元素进行排序
#define x first
#define y second
typedef pair<int,int> PII;
完整代码实现:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N = 100010;
int n,d,k;//读入的个数,时间段,赞的范围
int cnt[N];//记录每个id下帖子赞的数量
PII logs[N];//记录读入的每个数据(first为时刻,second为id)
bool st[N];//判断状态数组,看是否满足热帖状态
int main()
{
scanf("%d%d%d",&n,&d,&k);
for(int i=0;i<n;i++) scanf("%d%d",&logs[i].x,&logs[i].y);
sort(logs,logs+n);//对每个二元组按时间排序
for(int i=0,j=0;i<n;i++)
{
int id = logs[i].y;//拿出每个赞对应的id,赞的数量++
cnt[id] ++;
while(logs[i].x - logs[j].x >= d) //第i个帖子和第j个帖子的时间间隔如果超出规定的时间段
{
cnt[logs[j].y] --;//减去边界帖子
j++;
}
if(cnt[id] >= k) st[id] = true; //判断是否满足热帖
}
for(int i=0;i<N;i++)
{
if(st[i]) printf("%d\n",i);
}
return 0;
}