2025-04-21
JAVA
0

目录

引言
问题分析
Java实现详解
1. 数据结构设计
2. 核心算法实现
3. 自定义排序实现
4. 完整代码
算法复杂度分析
实际应用扩展
总结
思考题

引言

在现代企业管理中,员工培训和学习活动的参与度是衡量员工积极性的重要指标。很多公司会组织新员工进行每日打卡学习活动,并希望通过数据分析找出表现最积极的员工。本文将详细介绍如何使用Java实现一个员工打卡统计系统,找出打卡次数最多的TOP5员工。

问题分析

我们需要解决的问题可以分解为以下几个部分:

  1. 输入处理:读取员工数量、每日打卡数据
  2. 数据存储:记录每个员工的打卡次数和首次打卡时间
  3. 排序规则:按照特定规则对员工进行排序
  4. 结果输出:输出打卡次数最多的前5名员工

Java实现详解

1. 数据结构设计

我们使用HashMap来存储员工打卡记录,键是员工ID,值是一个包含两个元素的数组:

java
Map<Integer, int[]> employeeRecords = new HashMap<>();

其中:

  • int[0]存储打卡次数
  • int[1]存储首次打卡日期(0-29表示30天)

2. 核心算法实现

java
// 读取30天的打卡数据 for (int day = 0; day < 30; day++) { String[] idsStr = scanner.nextLine().split(" "); for (String idStr : idsStr) { int id = Integer.parseInt(idStr); if (!employeeRecords.containsKey(id)) { // 新员工:打卡次数=1,首次打卡日期=当前day employeeRecords.put(id, new int[]{1, day}); } else { // 已有员工:打卡次数+1,首次打卡日期不变 int[] record = employeeRecords.get(id); record[0]++; } } }

3. 自定义排序实现

排序规则是本题的核心难点,我们需要实现三级排序:

  1. 打卡次数降序
  2. 首次打卡日期升序
  3. 员工ID升序
java
Collections.sort(entries, new Comparator<Map.Entry<Integer, int[]>>() { @Override public int compare(Map.Entry<Integer, int[]> a, Map.Entry<Integer, int[]> b) { int[] recordA = a.getValue(); int[] recordB = b.getValue(); // 1. 比较打卡次数(降序) if (recordA[0] != recordB[0]) { return Integer.compare(recordB[0], recordA[0]); } // 2. 比较首次打卡日期(升序) else if (recordA[1] != recordB[1]) { return Integer.compare(recordA[1], recordB[1]); } // 3. 比较员工ID(升序) else { return Integer.compare(a.getKey(), b.getKey()); } } });

4. 完整代码

java
import java.util.*; public class EmployeeAttendance { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 读取员工数量N int N = scanner.nextInt(); scanner.nextLine(); // 消耗换行符 // 读取30天的打卡员工数量(题目要求但实际不需要使用) scanner.nextLine(); // 创建员工打卡记录:员工ID -> [打卡次数, 首次打卡日期] Map<Integer, int[]> employeeRecords = new HashMap<>(); // 读取30天的打卡数据 for (int day = 0; day < 30; day++) { String[] idsStr = scanner.nextLine().split(" "); for (String idStr : idsStr) { int id = Integer.parseInt(idStr); if (!employeeRecords.containsKey(id)) { // 新员工:打卡次数=1,首次打卡日期=当前day employeeRecords.put(id, new int[]{1, day}); } else { // 已有员工:打卡次数+1,首次打卡日期不变 int[] record = employeeRecords.get(id); record[0]++; } } } // 转换为List以便排序 List<Map.Entry<Integer, int[]>> entries = new ArrayList<>(employeeRecords.entrySet()); // 自定义排序 Collections.sort(entries, new Comparator<Map.Entry<Integer, int[]>>() { @Override public int compare(Map.Entry<Integer, int[]> a, Map.Entry<Integer, int[]> b) { int[] recordA = a.getValue(); int[] recordB = b.getValue(); // 1. 比较打卡次数(降序) if (recordA[0] != recordB[0]) { return Integer.compare(recordB[0], recordA[0]); } // 2. 比较首次打卡日期(升序) else if (recordA[1] != recordB[1]) { return Integer.compare(recordA[1], recordB[1]); } // 3. 比较员工ID(升序) else { return Integer.compare(a.getKey(), b.getKey()); } } }); // 输出TOP5(或更少) int count = Math.min(5, entries.size()); for (int i = 0; i < count; i++) { if (i > 0) { System.out.print(" "); } System.out.print(entries.get(i).getKey()); } } }

算法复杂度分析

  • 时间复杂度:O(N + MlogM),其中N是总打卡记录数,M是有打卡记录的员工数
  • 空间复杂度:O(M),需要存储所有有打卡记录的员工信息

实际应用扩展

这个基础算法可以扩展应用到许多实际场景:

  1. 员工考勤统计:统计月度出勤情况
  2. 学习平台活跃度分析:找出最活跃的学习者
  3. 用户行为分析:识别高频使用某功能的用户

总结

通过这个案例,我们学习了:

  1. 如何使用合适的数据结构存储复杂信息
  2. 如何实现多级排序规则
  3. Java中集合框架的实际应用

这种类型的问题在编程面试中也经常出现,掌握这类问题的解决方法对提升编程能力很有帮助。

思考题

  1. 如果打卡数据量非常大(比如数万员工,一年数据),如何优化这个算法?
  2. 如果需要实时更新和查询TOP5,应该如何设计系统?
  3. 如果要找出连续打卡天数最多的员工,算法应该如何修改?

欢迎在评论区分享你的想法和解决方案!