版权声明:本文为博主原创文章,未经博主允许不得转载。
一、问题描述
小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有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
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。不要使用package语句。不要使用jdk1.7及以上版本的特性。主类的名字必须是:Main,否则按无效代码处理。
二、题目类型:编程大题、排序、尺取法
三、解题思路及代码
这道题人眼看着觉得挺容易,但是怎么用程序准确表达出来呢?我想了很久,不太会。。。最后试着用暴力破解。。。我甚至还单独写了一个Blog类(微笑.jpg)
1 import java.util.HashSet; 2 import java.util.Scanner; 3 import java.util.Set; 4 5 public class LogStatistics { 6 7 public static void main(String[] args) { 8 9 Scanner input = new Scanner(System.in); 10 int n = input.nextInt(); 11 int d = input.nextInt();// 以秒为单位 12 int k = input.nextInt(); 13 Blog[] arr = new Blog[n]; 14 for (int i = 0; i < arr.length; i++) { 15 arr[i] = new Blog(); 16 arr[i].setTime(input.nextInt()); 17 arr[i].setId(input.nextInt()); 18 } 19 20 Set<Integer> set = new HashSet<>();// 无序、不重复 21 for (int i = 0; i < arr.length; i++) {//遍历每一行数据 22 int count = 1; 23 for (int j = i + 1; j < arr.length; j++) { 24 if (arr[i].id == arr[j].id && arr[j].time - arr[i].time < d) { 25 count++; 26 } 27 } 28 if (count >= k) { 29 set.add(arr[i].id); 30 } 31 } 32 System.out.println(set.toString()); 33 34 } 35 } 36 37 class Blog { 38 int time; 39 int id; 40 41 public void setTime(int seconds) { 42 this.time = seconds; 43 } 44 45 public void setId(int id) { 46 this.id = id; 47 } 48 49 public String toString() { 50 return time + " " + id; 51 } 52 }
以上代码在数据量小的时候还勉强可以通过,一旦数据大了肯定会超时。。。所以我重新写,还用到了一些框架。
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.Comparator; 4 import java.util.HashSet; 5 import java.util.Iterator; 6 import java.util.List; 7 import java.util.Scanner; 8 import java.util.Set; 9 import java.util.TreeSet; 10 11 public class LogStatistics { 12 13 public static void main(String[] args) { 14 Scanner input = new Scanner(System.in); 15 int n = input.nextInt();//有n条日志 16 int d = input.nextInt();// 以秒为单位 17 int k = input.nextInt();//热帖标准 18 int[][] arr = new int[n][2];//用二维数组存储数据 19 for (int i = 0; i < n; i++) { 20 for (int j = 0; j < 2; j++) { 21 arr[i][j] = input.nextInt(); 22 } 23 } 24 Set<Integer> set = new HashSet<>();//给id分类,HashSet 无序、不重复 25 for (int i = 0; i < n; i++) { 26 set.add(arr[i][1]); 27 } 28 Set<Integer> treeset = new TreeSet<>();//存热帖id,TreeSet 自动排序、不重复 29 Iterator<Integer> iter = set.iterator();//遍历每个id 30 while (iter.hasNext()) { 31 int id = iter.next(); 32 int count = 1;//记录点赞次数,每次初始化为1,因为一个id本身就是一次点赞 33 List<Integer> time = new ArrayList<>();//存当前id收到点赞的时间 34 for (int i = 0; i < n; i++) {//遍历所有的数据,找到与当前id相等的值,并存储时间 35 if (arr[i][1] == id) { 36 time.add(arr[i][0]); 37 } 38 } 39 Collections.sort(time);//将时间按升序排序 40 System.out.println(time.toString()); //我用来测试时间输出正确与否 41 for (int i = 0; i < time.size() - 1; i++) {//遍历时间链表 42 for(int j=i+1; j< time.size(); j++) {// 遍历第 i 个以后的每个时间元素 43 if(Math.abs(time.get(i) - time.get(j)) < d) {//如果它们的差 < 给定的时间段 44 count++;//“合法”点赞次数自增 1 45 } else { 46 break;//否则此时间段里达不成热帖或者已经达成热帖 47 } 48 } 49 if (count >= k) {//如果达成热帖,就把该 id 加入treeset 50 treeset.add(id); 51 break; 52 } 53 //达不成热帖,进入下一次循环,探寻下一个时间段里是否可以成为热帖 54 } 55 } 56 Iterator<Integer> result = treeset.iterator(); 57 while(result.hasNext()) { 58 System.out.println(result.next()); 59 } 60 } 61 }
但是吧。。。我觉得没有优化到哪里去。。。。尺取法我还不会。。。(哭.jpg)