【蓝桥杯2018JavaB】日志统计

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:
ts id
表示在ts时刻编号id的帖子收到一个"赞"。
现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。
给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。
【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。
对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000
【输出格式】
按从小到大的顺序输出热帖id。每个id一行。
【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
【输出样例】
1
3
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

还是先提供我的思路,我想的很简单,用Map的key保存编号,value就用ArrayList保存。接受完数据,然后对每一个key的ArrayList进行排序遍历,求出在时间差值小于D的最大数量,也就是在D时间内某文章获得的最大的赞数,如果这个最大的赞数大于等于K,那么就打印。思路还是很清晰的,有了思路,代码是十分明朗的。就不写注释了。

public class Main{
	public static void main(String[] args) {			
		Scanner sc=new Scanner(System.in);
		int N=sc.nextInt();
		int D=sc.nextInt();
		int K=sc.nextInt();
		Map<Integer,List>map=new HashMap<>();
		for(int i=0;i<N;i++) {
			int value=sc.nextInt();
			int key=sc.nextInt();
			if(map.get(key)==null) {
				List<Integer>list = new ArrayList<>();
				list.add(value);
				map.put(key, list);
			}else {
				map.get(key).add(value);
			}
		}
		Set<Integer>set = map.keySet();
		for(Integer key:set) {
			List<Integer>list =map.get(key);
			int size=list.size();
			if(size<K)break;
			Collections.sort(list);
			int likes=1,maxLikes=1;
			for(int i=0;i<size-1;i++){
				for(int j=i+1;j<size;j++) {
					if(list.get(j)-list.get(i)<D) {
						likes++;
					}
				}
				maxLikes=Math.max(maxLikes, likes);
			}
			if(maxLikes>=K)System.out.println(key);
		}
	}
}

然后提供网络的答案。


public class A08_日志统计 {
 
	// 存日志数据, ts-td分别是时刻及id,组合成对象, 存储在R中
	static class R { // 定义内部类
		int ts, td;// 时刻及id
	}
 
	public static void main(String[] args) throws FileNotFoundException {
//		System.setIn(new FileInputStream("E:\\in8.txt"));
//		System.setOut(new PrintStream("E:\\out8.txt"));
 
		Scanner sc = new Scanner(System.in);
		int N = sc.nextInt(), D = sc.nextInt(), K = sc.nextInt();
		R[] rs = new R[N];
		for (int i = 0; i < N; i++) {// 读取日志数据
			R r = new R();
			r.ts = sc.nextInt();
			r.td = sc.nextInt();
			rs[i] = r;
		}
		// 匿名内部类 定义 排序器   自定义 比较器
		Arrays.sort(rs, new Comparator<R>() {
			// 按照时刻ts对一个记录R做升序排序
			@Override
			public int compare(R r1, R r2) {
				return r1.ts - r2.ts;
			}
		});
 
		// cnt: 用于给id计数 记录id及其出现的次数
		Map<Integer, Integer> cnt = new HashMap<Integer, Integer>();
 
		// answers: 用于存储答案(各个id), 因为要求答案输出有序, 这里直接用TreeSet
		SortedSet<Integer> answers = new TreeSet<Integer>();
 
		// 尺取法【通常是:双指针】
		int j = 0;// 移动哨兵---用于探测的指针
		for (int i = 0; i < N; ++i) {// i: 尺取法的起点---头部
			// 循环条件: i指向的时刻-i指向的时刻 < D
			while (j < N && rs[j].ts - rs[i].ts < D) {
				int td = rs[j].td;
				Integer exist = cnt.get(td);
				// 每一次循环,都要统计id,计数
				if (exist != null) {
					cnt.put(td, exist + 1);
				} else {
					cnt.put(td, 1);// id第一次出现
				}
				// 判断id数是否 >= K【判断是否满足条件】id放入answers中
				if (cnt.get(td) >= K) {
					answers.add(td);
				}
				j++;
			}
			// (马上i就要更新了)将上一个i对应的id的计数-1
			// 上一个区间, td的计数要扣除, 不干扰下一个区间的统计
			Integer cntOfI = cnt.get(rs[i].td);
			if (cntOfI != null) {
				cnt.put(rs[i].td, cntOfI - 1);
			}
		}
		// 输出答案---输出各个id
		for (Integer i : answers) {
			System.out.println(i);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值