小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有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);
}
}
}