lanqiao 179 日志统计(2018年第九届蓝桥杯省赛C++B组)或acwing 1238

题目:

算法补充:

双指针:这题主要是在一个滑动的区间内(和acwing799 最长连续不重复序列 很相似)

模板:

for (int i = 0, j = 0; i < n; i ++ )  // j从某一位置开始,不一定是0
{
    while (j < i && check(i, j)) 
          {
                // 具体问题的逻辑
                j++;
          }

}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间,比如快排的划分过程
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

分析思考:

一开始我是看了算法标签,用双指针的方法,但是后来我不会写,尝试使用暴力,发现没结果。原因:一是逻辑,考虑错了题目要求的是时间段内,而我把他当作超过某个时间就可以了。二是语法,数组问题,把cnt[]计算出来的结果赋给另一个数组,导致输出上有点错误。后来借鉴了别人的代码,还是有点看不懂,我不理解别人代码中的while()限制循环里面为啥它没有限制id相同,就减去时间差呢?请看我难点那里的解释。

易错点:

  1. 题目要求的时间段是左闭右开。

难点:

如何写while()后面的内容。

sort(num,num+n,cmp_score);  //默认升序排序  !!!等下总结+看
	for(int i=0,j=0;i<n;i++)   //i走在前面 
		{
			cnt[num[i].id]++;
			while(num[i].ts-num[j].ts>=d&&j<i)  //因为那个区间,d是不包括的 
				{
					cnt[num[j].id]--;
					j++; 
				}
			if (cnt[num[i].id] >= k)
            st[num[i].id] = true;
		 } 

首先对数组按照时间上的一个排序(这个问题和acwing799 最长连续不重复序列有点不同),通过对时间区间上的处理,一旦时间>=给定时间范围的话,那么就要把前面的计数全部删除,不考虑id是否对应的原因的:因为即使后面(给定时间范围的后面)再出现了同样的id,到这个时候再去删除的话,写出来的代码就会超时,两个循环,干脆直接前面就删除掉。----->同样这也解释了为什么要先对数组进行一个时间上的排序,只有排序了才能解决这个超时间区域,删除前面所有的计数。

学习:

语法点:

  1. 结构体好久没写。这个是结构体数组,引用的时候就直接用num[1].ts这样子
struct number
{
	int ts;  //存放时间 
	int id;
}num[N];

     2. bool类型的数组我也比较少使用,后面的代码是很好的解释。

bool st[N];

内置函数:

sort函数的使用见这篇文章C++ sort()排序详解-CSDN博客

注意的是对于这次的函数,struct number才是变量类型,不是num!!!,可以直接用number作为变量类型。

代码:

  1. 初始:
//lanqiao 179 日志统计 或者 acwing 1238
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std; 
const int N=100010;
int n,d,k;  //n是数据个数,d是时间,k是赞 
int cnt[N];
bool st[N]; //用于存储每个帖子是否是热帖,所以用bool类型
struct number
{
	int ts;  //存放时间 
	int id;
}num[N];
//升序排序 
bool cmp_score(number x,number y)//!!!这里用number才行,用num不行的 
{
	return x.ts < y.ts;
}
int main()
{
	scanf("%d%d%d",&n,&d,&k);
	//定义结构体数组 
	
	for(int i=0;i<n;i++)
		{
			scanf("%d%d",&num[i].ts,&num[i].id);
		//	getchar();
		 } 
	//排序!!!区别之前写的第一个双指针实验
	sort(num,num+n,cmp_score);  //默认升序排序  !!!等下总结+看
	for(int i=0,j=0;i<n;i++)   //i走在前面 
		{
			cnt[num[i].id]++;
			while(num[i].ts-num[j].ts>=d&&j<i)  //因为那个区间,d是不包括的 
				{
					cnt[num[j].id]--;
					j++; 
				}
			if (cnt[num[i].id] >= k)
            st[num[i].id] = true;
		 } 
	    for(int i = 0; i < 100000; i ++)
    {
        if(st[i])//如果为真,则把热帖的id打印出来
            cout << i << endl;
    }
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值