找出所有成绩恰好在中位数水平的员工
背景介绍
某公司举办了一场全员技能竞赛,现在需要对成绩进行分析。其中一项重要的分析指标是找出所有成绩恰好在中位数水平的员工,以便进一步了解中间梯队的人员情况。
核心概念
-
员工记录 (Employee Record):
- 每一条记录包含员工的
name(姓名) 和score(分数)。 - 姓名是唯一的。
- 每一条记录包含员工的
-
中位数定义 (Median Definition):
-
这是本题的一个特殊规则,请务必注意。
-
首先,将所有员工的分数收集起来并按从小到大的顺序排列。
-
然后,根据分数的总个数来确定中位数:
- 如果分数总个数是奇数: 中位数就是排序后位于最中间的那个分数。
- 如果分数总个数是偶数: 中位数是排序后位于中间的两个分数中较小的那个。
-
任务要求
- 根据所有员工的分数,计算出中位数分数。
- 找出所有分数等于这个中位数分数的员工。
- 将这些员工的姓名按其在原始输入中的顺序倒序排列。
- 返回最终的姓名列表。
解答要求
- 时间限制: 1000ms
- 内存限制: 256MB
输入格式
-
employeeList: 一个员工记录列表。1 <= employeeList.length <= 100employeeList[i].name: 字符串,仅由英文字母和数字组成,长度[1, 10],姓名不重复。employeeList[i].score: 整数,0 <= score <= 100。
输出格式
- 一个由分数等于中位数的员工姓名组成的字符串,姓名之间用单个空格分隔。
样例
输入样例 1
[["A02", 34], ["Li01", 32], ["B03", 34], ["C04", 56], ["A05", 79]]
输出样例 1
B03 A02
样例 1 解释
-
步骤 1 & 2: 提取并排序所有分数
- 原始分数列表:
[34, 32, 34, 56, 79] - 排序后:
[32, 34, 34, 56, 79]
- 原始分数列表:
-
步骤 3: 计算中位数
- 共有 5 个分数(奇数个)。
- 排序后最中间(第 3 个)的数是 34。所以中位数为 34。
-
步骤 4: 查找匹配员工
-
遍历原始输入列表,找到所有分数为 34 的员工。他们是:
"A02"(在输入的第 0 个位置)"B03"(在输入的第 2 个位置)
-
-
步骤 5: 按规则排序结果
- 题目要求按输入顺序的逆序输出。
- 在输入中,
"B03"的出现位置比"A02"晚。 - 因此,逆序排列后,
"B03"在前,"A02"在后。
-
最终输出:
"B03 A02"
输入样例 2
[["01", 10], ["1b", 10], ["2a", 9], ["02", 9]]
输出样例 2
02 2a
样例 2 解释
- 排序分数:
[9, 9, 10, 10] - 计算中位数: 共有 4 个分数(偶数个)。中间两个数是
9和10。根据规则,取较小的那个,所以中位数为 9。 - 查找匹配员工: 分数为 9 的员工是
"2a"和"02"。 - 排序结果: 在输入中,
"02"在"2a"之后。按输入顺序逆序,"02"在前。 - 最终输出:
"02 2a"
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* 解决“中位数成绩”问题的实现类.
*/
public class MedianScoreFinder {
/**
* 内部静态类,用于表示一名员工.
* 封装了员工的姓名、分数以及其在原始输入数组中的索引。
* 记录原始索引是实现“按输入顺序逆序输出”的关键。
*/
private static class Employee {
String name;
int score;
int originalIndex; // 员工在输入列表中的原始位置
public Employee(String name, int score, int originalIndex) {
this.name = name;
this.score = score;
this.originalIndex = originalIndex;
}
}
/**
* 主方法,计算分数中位数,并返回分数等于中位数的员工姓名列表.
* @param employeeData 输入的员工数据,格式为 [[name, score], ...]
* @return 按输入顺序逆序排列的、分数等于中位数的员工姓名列表
*/
public List<String> findMedianEmployees(Object[][] employeeData) {
// --- 步骤 1: 解析输入,并创建员工对象列表 ---
List<Employee> employees = new ArrayList<>();
List<Integer> scores = new ArrayList<>();
for (int i = 0; i < employeeData.length; i++) {
String name = (String) employeeData[i][0];
int score = (Integer) employeeData[i][1];
employees.add(new Employee(name, score, i));
scores.add(score);
}
// --- 步骤 2: 对分数列表进行排序,以计算中位数 ---
Collections.sort(scores);
// --- 步骤 3: 根据题目定义计算中位数 ---
int medianScore;
int n = scores.size();
if (n % 2 != 0) {
// 如果员工数量是奇数,中位数是排序后最中间的那个数
medianScore = scores.get(n / 2);
} else {
// 如果员工数量是偶数,中位数是中间两个数中较小的那个
// 中间两个数的索引是 (n/2 - 1) 和 (n/2)
medianScore = scores.get(n / 2 - 1);
}
// --- 步骤 4: 筛选出所有分数等于中位数的员工 ---
List<Employee> medianEmployees = new ArrayList<>();
for (Employee emp : employees) {
if (emp.score == medianScore) {
medianEmployees.add(emp);
}
}
// --- 步骤 5: 按输入顺序的逆序对结果进行排序并提取姓名 ---
// 通过比较员工的 originalIndex 进行降序排序,即可实现“按输入顺序逆序”
medianEmployees.sort(Comparator.comparingInt((Employee emp) -> emp.originalIndex).reversed());
// 使用 Stream API 将排好序的员工对象列表映射为其姓名列表
return medianEmployees.stream()
.map(emp -> emp.name)
.collect(Collectors.toList());
}
}