计算特殊定义的中位数

96 阅读4分钟

计算特殊定义的中位数

背景介绍

在数据处理和分析中,我们常常需要根据一批数据的统计特性(如中位数)来设定一个阈值,以便进行后续的计算或过滤。本题要求您实现一个特定的阈值计算方法。

任务要求

给定一个无序的数字序列,请严格按照以下两个步骤计算并返回一个特殊定义的中位数:

第一步:筛选数据
  1. 首先,对完整的输入数字序列进行升序排序

  2. 然后,只保留排序后前三分之一的数字。

  3. 注意: 三分之一的数量需要向上取整

    • 例如,如果序列有 10 个数字,三分之一是 3.33,向上取整为 4。我们就需要取出排序后的前 4 个数字。
    • 如果序列有 9 个数字,三分之一是 3,向上取整还是 3。我们就取出排序后的前 3 个数字。
第二步:计算中位数
  1. 接下来,对第一步筛选出的这部分数字(我们称之为“子序列”)计算中位数。

  2. 中位数计算规则:

    • 如果子序列的数字个数是奇数,则中位数就是排序后(因为子序列已是排序好的)最中间的那个数。
    • 如果子序列的数字个数是偶数,则中位数是中间两个数的平均值,并且结果需要向上取整

解答要求

  • 时间限制: 1000ms
  • 内存限制: 256MB

输入格式

  • 一个整数数组 arr,代表数据序列。

    • 1 <= arr.length <= 1000
    • 1 <= arr[i] <= 100000

输出格式

  • 一个整数,表示所求的中位数。

样例

输入样例 1

[2, 3, 1, 6, 1, 10, 2, 5, 9, 8]

输出样例 1

2

样例 1 解释

  1. 原始序列: [2, 3, 1, 6, 1, 10, 2, 5, 9, 8]

    • 总共有 10 个数字。
  2. 步骤 1 - 筛选数据:

    • 对原始序列排序: [1, 1, 2, 2, 3, 5, 6, 8, 9, 10]
    • 计算前三分之一的数量: ceil(10 / 3.0) = ceil(3.33) = 4
    • 取出排序后的前 4 个数,得到子序列: [1, 1, 2, 2]
  3. 步骤 2 - 计算中位数:

    • 子序列 [1, 1, 2, 2] 的个数为 4 (偶数)。
    • 中间的两个数是第 2 个数 (1) 和第 3 个数 (2)。(数组索引为 1 和 2)
    • 计算平均值: (1 + 2) / 2.0 = 1.5
    • 平均值向上取整: ceil(1.5) = 2
  4. 最终输出: 2


输入样例 2

[1000]

输出样例 2

1000

解释:

  1. 原始序列: [1000],长度为 1。
  2. 筛选数据: ceil(1 / 3.0) = 1。取出前 1 个数,子序列为 [1000]
  3. 计算中位数: 子序列个数为 1 (奇数),中位数就是最中间的数 1000
  4. 最终输出: 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;
        }
    }
}