计算特殊定义的中位数
背景介绍
在数据处理和分析中,我们常常需要根据一批数据的统计特性(如中位数)来设定一个阈值,以便进行后续的计算或过滤。本题要求您实现一个特定的阈值计算方法。
任务要求
给定一个无序的数字序列,请严格按照以下两个步骤计算并返回一个特殊定义的中位数:
第一步:筛选数据
-
首先,对完整的输入数字序列进行升序排序。
-
然后,只保留排序后前三分之一的数字。
-
注意: 三分之一的数量需要向上取整。
- 例如,如果序列有 10 个数字,三分之一是 3.33,向上取整为 4。我们就需要取出排序后的前 4 个数字。
- 如果序列有 9 个数字,三分之一是 3,向上取整还是 3。我们就取出排序后的前 3 个数字。
第二步:计算中位数
-
接下来,对第一步筛选出的这部分数字(我们称之为“子序列”)计算中位数。
-
中位数计算规则:
- 如果子序列的数字个数是奇数,则中位数就是排序后(因为子序列已是排序好的)最中间的那个数。
- 如果子序列的数字个数是偶数,则中位数是中间两个数的平均值,并且结果需要向上取整。
解答要求
- 时间限制: 1000ms
- 内存限制: 256MB
输入格式
-
一个整数数组
arr,代表数据序列。1 <= arr.length <= 10001 <= arr[i] <= 100000
输出格式
- 一个整数,表示所求的中位数。
样例
输入样例 1
[2, 3, 1, 6, 1, 10, 2, 5, 9, 8]
输出样例 1
2
样例 1 解释
-
原始序列:
[2, 3, 1, 6, 1, 10, 2, 5, 9, 8]- 总共有 10 个数字。
-
步骤 1 - 筛选数据:
- 对原始序列排序:
[1, 1, 2, 2, 3, 5, 6, 8, 9, 10] - 计算前三分之一的数量:
ceil(10 / 3.0)=ceil(3.33)=4。 - 取出排序后的前 4 个数,得到子序列:
[1, 1, 2, 2]。
- 对原始序列排序:
-
步骤 2 - 计算中位数:
- 子序列
[1, 1, 2, 2]的个数为 4 (偶数)。 - 中间的两个数是第 2 个数 (
1) 和第 3 个数 (2)。(数组索引为 1 和 2) - 计算平均值:
(1 + 2) / 2.0 = 1.5。 - 平均值向上取整:
ceil(1.5) = 2。
- 子序列
-
最终输出:
2。
输入样例 2
[1000]
输出样例 2
1000
解释:
- 原始序列:
[1000],长度为 1。 - 筛选数据:
ceil(1 / 3.0) = 1。取出前 1 个数,子序列为[1000]。 - 计算中位数: 子序列个数为 1 (奇数),中位数就是最中间的数
1000。 - 最终输出:
1000。
import java.util.Arrays;
/**
* 实现一个特殊的中位数计算器.
* 该计算器首先对数据进行排序,然后只考虑前三分之一的数据来计算中位数。
*/
public class MedianCalculator {
/**
* 主方法,根据题目定义的规则计算中位数.
* @param arr 一个无序的数字序列
* @return 计算出的中位数
*/
public int calculateThresholdMedian(int[] arr) {
// --- 步骤 1: 对整个输入数组进行从小到大排序 ---
// 这是后续所有计算的基础。
Arrays.sort(arr);
// --- 步骤 2: 计算前三分之一(向上取整)的数字个数 ---
// 这是一个计算 ceil(n/3) 的整数运算技巧。加2是为了向上取整,如果分母是n,则要加n-1
// 例如:
// - 10个数字, (10 + 2) / 3 = 4
// - 9个数字, (9 + 2) / 3 = 3 (向下取整是3,这里结果也是3)
// - 8个数字, (8 + 2) / 3 = 3
int subArraySize = (arr.length + 2) / 3;
// --- 步骤 3: 根据子序列的长度是奇数还是偶数,计算中位数 ---
// 检查子序列的数字个数是否为奇数
if (subArraySize % 2 != 0) {
// 如果是奇数,中位数就是最中间的那个数。
// 在0-based索引中,中间位置的索引是 subArraySize / 2。
// 例如,5个数,索引是0,1,2,3,4,中间是索引2 (5/2=2)。
int middleIndex = subArraySize / 2;
return arr[middleIndex];
} else {
// 如果是偶数,中位数是中间两个数的平均值(向上取整)。
// 在0-based索引中,中间两个数的位置是 (subArraySize / 2 - 1) 和 (subArraySize / 2)。
// 例如,4个数,索引是0,1,2,3,中间是索引1和2。
int middleIndex1 = subArraySize / 2 - 1;
int middleIndex2 = subArraySize / 2;
int num1 = arr[middleIndex1];
int num2 = arr[middleIndex2];
// 计算平均值并向上取整。
// (a + b + 1) / 2 是两个整数平均值向上取整的常用技巧。
// 例如:
// - (1 + 2 + 1) / 2 = 2
// - (2 + 2 + 1) / 2 = 2 (整数除法)
return (num1 + num2 + 1) / 2;
}
}
}