异常的打卡记录

题目描述

考勤记录是分析和考核职工工作时间利用情况的原始依据,也是计算职工工资的原始依据,为了正确地计算职工工资和监督工资基金使用情况,公司决定对员工的手机打卡记录进行异常排查。如果出现以下两种情况,则认为打卡异常:实际设备号与注册设备号不一样 或者,同一个员工的两个打卡记录的时间小于60分钟并且打卡距离超过5km。 给定打卡记录的字符串数组 clockRecords(每个打卡记录组成为:工号;时间(分钟);打卡距离(km);实际设备号;注册设备号),返回其中异常的打卡记录(按输入顺序输出)

输入描述

第一行输入为N,表示打卡记录数;

之后的N行为打卡记录,每一行为一条打卡记录。

备注

  • clockRecords长度 ≤ 1000
  • clockRecords[i] 格式:{id},{time},{distance},{actualDeviceNumber},{registeredDeviceNumber} id由6位数字组成 time由整数组成,范围为0 ~ 1000 distance由整数组成,范围为0 ~100 actualDeviceNumber与registeredDeviceNumber由四位大写字母组成.

输出描述

输出异常的打卡记录

用例1

输入

2
100000,10,1,ABCD,ABCD
100000,50,10,ABCD,ABCD

输出

100000,10,1,ABCD,ABCD;100000,50,10,ABCD,ABCD

用例2

输入

2
100000,10,1,ABCD,ABCD
100001,80,10,ABCE,ABCE

输出

null

用例3

输入

输出

100000,80,10,ABCE,ABCD

思路:

1. 对于每一条打卡记录,实际设备号与注册设备号不一样则视为异常打卡

2.对于两个打卡记录比较,注意:正常的打卡记录最多只能有两条!因此对于同一个员工号,所有记录都要跟自己的第一条记录比较。

3.使用hashmap 存储每一个员工的打卡记录列表,以及输入顺序。

4.结果一定要去重,使用set保存结果。最后按照输入顺序 打印异常的打卡记录

package 模拟考试2;

import java.util.*;
import java.util.stream.Collectors;
//异常的打卡记录

/**
 1. 实际设备号与注册设备号不一样
 2.同一个员工的两个打卡记录的时间小于60分钟并且打卡距离超过5km。
    即同一员工的两次相近的打卡记录 时间小于60分钟、并且两次打卡的位置的距离超过5km。 如果超过2条打卡记录,所有记录都跟第一条进行比较!!!因为正常打卡只有2条
 3.防止重复记录,使用hashset
 4.返回其中异常的打卡记录(按输入顺序输出)
 */
public class Solution109 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n=Integer.parseInt(in.nextLine());
        HashMap<Integer, ArrayList<Emp>> map = new HashMap<>(); // {id,Emp}
        for (int i=0;i<n;i++){
            String[] str = in.nextLine().split(",");
            int id = Integer.parseInt(str[0]);
            int time = Integer.parseInt(str[1]);
            int distance = Integer.parseInt(str[2]);
            String actualDeviceNumber= str[3];
            String registeredDeviceNumber= str[4];
            Emp emp=new Emp(id,time,distance,actualDeviceNumber,registeredDeviceNumber,i+1);
            ArrayList<Emp> list = map.getOrDefault(id, new ArrayList<>());
            list.add(emp);
            map.put(id,list);
        }
         HashSet<Emp> set=new HashSet<>();

        for (Map.Entry<Integer, ArrayList<Emp>> entry : map.entrySet()) {
            ArrayList<Emp> list = entry.getValue();
            Emp first = list.get(0);
            //如果只有一次打卡记录,则只判断打卡设备和注册设备是否一致
            if (!first.actualDeviceNumber.equals(first.registeredDeviceNumber)){
                set.add(list.get(0));
            }
            for (int i=1;i<list.size();i++){
                Emp emp = list.get(i);
                //当前记录的打卡设备和注册设备是否一致
                if (!emp.actualDeviceNumber.equals(emp.registeredDeviceNumber)){
                    set.add(emp);
                }
                //全部跟第一次记录比较
                if ( Math.abs(emp.time-first.time)<60&& Math.abs(emp.distance-first.distance)>5){
                    set.add(first);
                    set.add(emp);
                }
            }
        }
        if (set.isEmpty()){
            System.out.println("null");
            return;
        }

        List<Emp> collect = set.stream().sorted(Comparator.comparingInt(o -> o.pos)).collect(Collectors.toList());
        StringBuilder builder = new StringBuilder();
        for (Emp emp : collect) {
            String a=emp.id+","+emp.time+","+emp.distance+","+emp.actualDeviceNumber+","+emp.registeredDeviceNumber+";";
            builder.append(a);
        }
        //去掉最后一个分号
        System.out.println(builder.deleteCharAt(builder.length() - 1));


    }



    //考勤信息
    static class Emp{
        int id;
        int time;
        int distance;
        String actualDeviceNumber;
        String registeredDeviceNumber;
        int pos; //输入顺序
        public Emp( int id, int time,int distance,String actualDeviceNumber,String registeredDeviceNumber,int pos){
            this.id=id;
            this.time=time;
            this.distance=distance;
            this.actualDeviceNumber=actualDeviceNumber;
            this.registeredDeviceNumber=registeredDeviceNumber;
            this.pos=pos;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值