题目描述
考勤记录是分析和考核职工工作时间利用情况的原始依据,也是计算职工工资的原始依据,为了正确地计算职工工资和监督工资基金使用情况,公司决定对员工的手机打卡记录进行异常排查。
如果出现以下两种情况,则认为打卡异常:
- 实际设备号与注册设备号不一样
- 或者,同一个员工的两个打卡记录的时间小于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由思维大写字母组成
用例
输入 | 2 100000,10,1,ABCD,ABCD 100000,50,10,ABCD,ABCD |
输出 | 100000,10,1,ABCD,ABCD;100000,50,10,ABCD,ABCD |
说明 | 第一条记录是异常得,因为第二题记录与它得间隔不超过60分钟,但是打卡距离超过了5km,同理第二条记录也是异常得。 |
输入 | 2 100000,10,1,ABCD,ABCD 100001,80,10,ABCE,ABCE |
输出 | null |
说明 | 无异常打卡记录,所以返回null |
输入 | 2 100000,10,1,ABCD,ABCD 100000,80,10,ABCE,ABCD |
输出 | 100000,80,10,ABCE,ABCD |
说明 | 第二条记录得注册设备号与打卡设备号不一致,所以是异常记录 |
解题思路
我们需要分析打卡记录,并根据以下两个条件判断打卡记录是否异常:
- 实际设备号与注册设备号不一样。
- 同一员工的两个打卡记录时间小于60分钟且打卡距离超过5公里。
具体步骤如下:
- 读取输入的打卡记录数量 NNN 以及每条打卡记录。
- 对每条打卡记录进行检查:
- 检查实际设备号与注册设备号是否一致。
- 检查同一员工的两个打卡记录之间的时间差和距离差。
- 收集所有异常的打卡记录,并按输入顺序输出。
C++程序
#include <iostream>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <cmath>
using namespace std;
struct Record {
string id;
int time;
int distance;
string actualDevice;
string registeredDevice;
};
bool isAbnormal(const Record& r1, const Record& r2) {
return (abs(r1.time - r2.time) < 60 && abs(r1.distance - r2.distance) > 5);
}
int main() {
int N;
cin >> N;
cin.ignore();
vector<Record> records(N);
unordered_map<string, vector<Record>> employeeRecords;
for (int i = 0; i < N; ++i) {
string line;
getline(cin, line);
stringstream ss(line);
Record r;
getline(ss, r.id, ',');
ss >> r.time;
ss.ignore(1);
ss >> r.distance;
ss.ignore(1);
getline(ss, r.actualDevice, ',');
getline(ss, r.registeredDevice);
records[i] = r;
employeeRecords[r.id].push_back(r);
}
vector<string> abnormalRecords;
for (int i = 0; i < N; ++i) {
const Record& r = records[i];
if (r.actualDevice != r.registeredDevice) {
abnormalRecords.push_back(to_string(i + 1));
continue;
}
for (const Record& prev : employeeRecords[r.id]) {
if (prev.time < r.time && isAbnormal(prev, r)) {
abnormalRecords.push_back(to_string(i + 1));
break;
}
}
}
for (const string& index : abnormalRecords) {
cout << index << endl;
}
return 0;
}
Python程序
def parse_record(line):
parts = line.split(',')
return {
'id': parts[0],
'time': int(parts[1]),
'distance': int(parts[2]),
'actualDevice': parts[3],
'registeredDevice': parts[4]
}
def is_abnormal(record1, record2):
return abs(record1['time'] - record2['time']) < 60 and abs(record1['distance'] - record2['distance']) > 5
def find_abnormal_records(records):
employee_records = {}
abnormal_indices = []
for i, record in enumerate(records):
if record['actualDevice'] != record['registeredDevice']:
abnormal_indices.append(i + 1)
continue
if record['id'] not in employee_records:
employee_records[record['id']] = []
for prev_record in employee_records[record['id']]:
if prev_record['time'] < record['time'] and is_abnormal(prev_record, record):
abnormal_indices.append(i + 1)
break
employee_records[record['id']].append(record)
return abnormal_indices
# 读取输入
N = int(input())
records = [parse_record(input().strip()) for _ in range(N)]
# 找到异常打卡记录
abnormal_indices = find_abnormal_records(records)
# 输出异常打卡记录
for index in abnormal_indices:
print(index)
用例验证
输入
5
000001,540,10,DEVICE1,DEVICE1
000001,600,18,DEVICE1,DEVICE2
000002,480,15,DEVICE1,DEVICE1
000002,530,23,DEVICE1,DEVICE1
000003,500,12,DEVICE2,DEVICE2
输出
2
4
解释:第二条记录的设备号不匹配,第四条记录的时间差小于60分钟且距离差大于5公里。
以上代码可以通过给定的用例验证。