算法——双指针

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;
}

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值