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

在这里插入图片描述

  • 专栏内容:蓝桥杯刷题
  • ⛪个人主页:子夜的星的主页
  • 座右铭:前路未远,步履不停

目录

  • 一、题目描述
    • 1.问题描述
    • 2.输入格式
    • 3.输出格式
    • 4.一个例子
  • 二、题目分析
    • 1、暴力法
    • 2、双指针
  • 三、代码汇总
    • 1、暴力代码汇总
    • 2、双指针代码汇总


一、题目描述

1.问题描述

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

2.输入格式

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

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;    //标记答案
        }
    }

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

【蓝桥杯基础题】2018年省赛—日志统计_第1张图片

2、双指针

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

    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,这样就能保证两个指针包围的窗口不会超过题目范围以外的数据。
【蓝桥杯基础题】2018年省赛—日志统计_第4张图片
【蓝桥杯基础题】2018年省赛—日志统计_第5张图片
写完之后去测一下 (总代码放在最后)
【蓝桥杯基础题】2018年省赛—日志统计_第6张图片

【蓝桥杯基础题】2018年省赛—日志统计_第7张图片

三、代码汇总

1、暴力代码汇总

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


你正在阅读 【子夜的星】 的博客
阅读完毕,可以点点小手赞一下
发现错误,直接评论区中指正吧

你可能感兴趣的:(#,蓝桥杯刷题,算法刷题笔记,蓝桥杯,算法,双指针,日志统计,暴力)