【蓝桥杯基础题】2018年省赛—日志统计

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【蓝桥杯基础题】2018年省赛—日志统计

一、题目描述

1.问题描述

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:
ts id,表示在ts时刻编号id的帖子收到一个"赞"。现在小明想统计有哪些帖子曾经是"热帖”。
如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻T满足该帖在$[T,T十D)$这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。

2.输入格式

输入格式:
第一行包含三个整数 N,D,K。
以下 N 行,每行一条日志,包含两个整数 ts 和 id。其中$1≤K≤N≤10^5$ , $0≤ts≤10^5,0≤id≤10^5$。

3.输出格式

按从小到大的顺序输出热帖 id。每个 id 一行。

4.一个例子

下面是一个样例

输入:

7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3

输出:

1
3

二、题目分析

先简单的说一下这道题的意思,就是在输入的数据中找出每个 [ 当前时间点,当前时间点+D) 这个时间的范围内,id出现的次数是不是大于等于K,如果在这些范围内大于等于K,最后就输出该id。
看一下给出的样例,7代表7行日志,10代表当前时间点+10这个范围,2表示出现id次数要大于2.

在[0,0+10) 这个范围内,输入的数据中出现了2次1,等于2,所以要输出它。
在[1,1+10)这个范围内,输入的数据中只出现了1次10,不符合。
在[91,91+10) 这个范围内,输入的数据中出现了2次3,等于2,所以2要输出它。

1、暴力法

看到这道题的第一个感觉就是,直接枚举出所有时间点的情况,然后再去判断是不是符合大于等于K的条件,如果符合条件,就标记它,最后一起输出。那这样就需要两层循环,第一层循环的范围是从0开始一直到输入数据中的最大时间,第二层循环就是判断每次的时间段中每个id出现的次数是不是大于等于K。(总代码放在最后)

 for (int time = 0; time <= Max_time; time++) //枚举时间
    {
        memset(cnt, 0, sizeof(cnt));         //每次的时间段都要重新计数
        for (int i = 1; i <= n; i++)    //枚举日志
        {
            int t = blog[i].ts;
            int id = blog[i].id;
            if (t >= time && t < time + d) //判断是不是符合时间范围
                cnt[id]++;
            if (cnt[id] >= k)        //判断是不是符合大于等于K
                hot[id] = true;    //标记答案
        }
    }

但是这样干虽然简单,但是时间复杂度有点高,不能完成所有的样例。

在这里插入图片描述

2、双指针

对双指针完全不了解的朋友可以看下这篇文章:双指针(尺取法):爱,是双向奔赴,还是你追我赶?
双指针中快慢指针题目的特点就是:每次循环都会看窗口(两个指针围起来的区间)是不是满足某个条件,如果满足,输出的是子区间的变形。
这道题中的范围$[T,T十D)$就是一个可以滑动的窗口,我们可以使用双指针中的快慢指针,再将输入的数据按照时间的排序后,不断地移动窗口,这样当处理到T时候,$[T,T十D)$这个窗口前面的数据就会被忽略。
以本题的输入的样例为例。我们先对该组数据按照时间进行排序:
在这里插入图片描述
然后定义两个指针,分别为指针i指针j
指针i作为快指针,遍历随时间而消失的帖子。指针j作为慢指针,根据题目的要求(指针i对于的时间-指针j对应的时间大于等于D),舍去T之前的帖子(指针j移动)。
在这里插入图片描述

    int i = 0; int j = 0;  //定义两个指针
    for (i = 0; i < n; i++) //快指针遍历
    {
        num[blog[i].id]++; //遍历过的每个帖子点赞数+1
        while (blog[i].ts - blog[j].ts >= d) //超出题目时间范围
        {
            num[blog[j].id]--;  //j指针指向的帖子点赞数-1
            j++;            //指针j向前移动
        }
    }

指针j每移动一步时候,就把其对应的帖子点赞数量减去1,这样就能保证两个指针包围的窗口不会超过题目范围以外的数据。
在这里插入图片描述
在这里插入图片描述
写完之后去测一下 (总代码放在最后)
在这里插入图片描述

在这里插入图片描述

三、代码汇总

1、暴力代码汇总

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
bool hot[N]; //判断是不是热帖
int cnt[N]; //记录点赞数
int n, d, k;
struct Blog
{
    int ts;
    int id;
}blog[N];
int main() {
    scanf("%d%d%d", &n, &d, &k);
    int Max_time = 0; 
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", &blog[i].ts, &blog[i].id);
        Max_time = max(blog[i].ts, Max_time); //获取输入的数据中的最大时间
    }

    for (int time = 0; time <= Max_time; time++) //枚举时间
    {
        memset(cnt, 0, sizeof(cnt)); //每次的时间段都要重新计数
        for (int i = 1; i <= n; i++) //枚举日志
        {
            int t = blog[i].ts; 
            int id = blog[i].id;
            if (t >= time && t < time + d) //判断是不是在范围之内
                cnt[id]++; 
            if (cnt[id] >= k)  //判断是不是符合热帖要求
                hot[id] = true; //标记为热帖
        }
    }
    for (int i = 0; i <= 1e5; i++)
        if (hot[i]) 
            printf("%d\n", i);
}

2、双指针代码汇总

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int num[N];    //记录帖子点赞数
bool hot[N]; //判断是不是热帖
int n, d, k; 
struct Blog 
{
    int ts; 
    int id;
}blog[N];

int cmp(Blog a, Blog b)//排序规则是按时间从小到大
{
    return a.ts < b.ts;
}
int main() {
    scanf("%d%d%d", &n, &d, &k);
    for (int i = 0; i < n; i++)
    {
        scanf("%d%d", &blog[i].ts, &blog[i].id);
    }
    sort(blog, blog + n,cmp);//排序
    int i = 0; int j = 0;
    for (i = 0; i < n; i++) //指针i开始遍历
    {
        num[blog[i].id]++; //遍历过的每个帖子点赞数+1
        while (blog[i].ts - blog[j].ts >= d)//超出题目时间范围
        {
            num[blog[j].id]--; //指针j指向的帖子点赞数-1
            j++; //指针j向前移动
        }
        if (num[blog[i].id] >= k) //如何符合标准
            hot[blog[i].id] = true; //标记为热帖
    }
    for (int i = 0; i < N; i++)
        if (hot[i] )
            printf("%d\n", i);
    return 0;
}
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
5月前
|
Java C语言 C++
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-87 字串统计
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-87 字串统计
35 0
|
5月前
|
人工智能 算法 Java
第十三届蓝桥杯B组Java(试题C:字符统计)
第十三届蓝桥杯B组Java(试题C:字符统计)
78 0
|
5月前
|
SQL 大数据 API
每天一道大厂SQL题【Day08】服务日志SQL统计
每天一道大厂SQL题【Day08】服务日志SQL统计
62 0
|
2月前
|
应用服务中间件 Linux nginx
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
|
4月前
|
Java
2022蓝桥杯大赛软件类省赛Java大学B组真题 刷题统计
2022蓝桥杯大赛软件类省赛Java大学B组真题 刷题统计
36 0
|
5月前
|
存储 弹性计算 运维
统计/var/log 有多少个文件
【4月更文挑战第29天】
49 1
|
5月前
|
C++
成绩统计(蓝桥杯)
成绩统计(蓝桥杯)
|
5月前
|
Java 程序员 C++
日志统计(蓝桥杯每日一题)
日志统计(蓝桥杯每日一题)
46 1
|
5月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-663 数字统计
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-663 数字统计
33 0
|
5月前
|
Java 程序员 C++
日志统计(每日一题)
日志统计(每日一题)
42 0