标题:日志统计
小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有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
作者:Pysrain
来源:CSDN
原文:https://blog.csdn.net/qq_39020387/article/details/79905912
版权声明:本文为博主原创文章,转载请附上博文链接!
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
public class 日志统计 {
/**
* @param args
*/
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();//帖子总数量
int d=sc.nextInt();//区间长度
int k=sc.nextInt();//不少于k个赞
Map<Integer,Integer> m=new TreeMap<>(new Comparator<Integer>() {
//重写compare方法,使Treemap可以放入相同健值的条目
@Override
public int compare(Integer o1, Integer o2) {
if(o1.equals(o2)){
return 1;//return 0;
}else {
return o1-o2;
}
}
});
for (int i = 1; i <= n; i++) {
int ts=sc.nextInt();
int id=sc.nextInt();
m.put(id,ts);
}
int x[]=new int[100001];//记录满足所有题干条件的id值
int num=0;//id数量
//遍历id
for (int id = 1; id < x.length; id++) {
if(check(m,id,d,k)){//是否满足
x[++num]=id;
}
}
//遍历输出结果
for (int i = 1; i <= num; i++) {
System.out.println(x[i]);
}
}
/**
* 确定此id是否为满足题干条件的id
* @param m 存储
* @param i id
* @param d 区间长度
* @param k 最少的赞个数
* @return
*/
private static boolean check(Map<Integer, Integer> m, int i, int d, int k) {
int count=0;//记录id出现的个数
LinkedList<Integer> list=new LinkedList<>();
for (Map.Entry<Integer, Integer> entry : m.entrySet()) {
if(entry.getKey()==i){
count++;
list.add(entry.getValue());//将key值也就是id,添加的list中
}
}
if(count<k){//id的个数小于要求的 最小赞的个数k
return false;
}
Collections.sort(list);
int st=0;//初始指针
int en=0;//结束指针
int sum=0;//当前赞的个数和
while (st<=en && en<list.size()) {
sum++;
if(sum>=k){//如果当前的赞的个数 >=k,也就是不少于k个赞
//判断时间区间是否符合在[T,T+d)之中
if(list.get(en)-list.get(st) < d){
return true;
}else {//不符合
st++;//初始指针右移
sum--;//当前赞数减1
}
}
//每次en指针都会右移,直到到达结尾
en++;
}
//如果超出了while循环的条件仍然没有返回的值,那么此id就不是‘热帖’
return false;
}
}
以下是自己写的代码:
import java.util.*;
public class Main{
public static int maxn = (int)1e6+10;
public static int[]ans = new int[maxn];
public static int n,d,k,ts,id,count,l,r,sum,cnt;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
d = scanner.nextInt();
k = scanner.nextInt();
Map<Integer,Integer> map = new TreeMap<>(
new Comparator<Integer>(){
public int compare(Integer o1,Integer o2){
if(o1.equals(o2)){
return 1;
}
else{
return o1-o2;
}
}
}
);
for(int i=0;i<n;i++){
ts = scanner.nextInt();
id = scanner.nextInt();
map.put(id,ts);
}
for(int i=1;i<=maxn;i++){
if(judge(i,map)){
ans[++cnt]=i;
}
}
//Arrays.sort(ans+1,ans+1+cnt);
for(int i=1;i<=cnt;i++){
System.out.println(ans[i]);
}
}
public static boolean judge(int i,Map<Integer,Integer>map){
count = 0;
List<Integer> list = new ArrayList<>();
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(entry.getKey()==i){
count++;
list.add(entry.getValue());
}
}
if(count<k){
return false;
}
Collections.sort(list);
l=0;
r=0;
sum=0;
while(l<=r&&r<=list.size()-1){
sum++;
if(sum>=k){
if(list.get(r)-list.get(l)<=d-1){
return true;
}else{
l++;
sum--;
}
}
r++;
}
return false;
}
}
笔记:
1.写了这道题,java的ArrayList,Collecitons,TreeMap,Comparator都练的差不多了。嗯,题目导向型学习集合知识。
2.下次定义maxn就用
public static int maxn = (int)1e6+10;
public static int[] a =new int[maxn];
//数组就直接用maxn定义
3.Map和List集合框架不能在静态区域定义,不然不能在函数动态区域里赋值,所以要在main里或者函数里地定义集合,如果main里定义的还必须得作为参数传到调用的方法里才行。
4.对象判断相等o1.equals(o2)
5.object类型可以作为任意类定义
6.如果java需要用vector存邻接表形式的键值对,就使用TreeMap修改compare方法改为可存相同key,存好后再用分别把每一个相同key的value通过map.entrySet()取出来并放到list里进行sort,同时记录相同key的个数,个数为0,说明没有这个key。最后和vector的邻接表效果一样,同样是对所有不同的key的分别对应的value进行排序。