Medium

题目描述

给你一个在范围 [0, 255] 内的整数的大样本。由于样本很大,用数组 count 表示,其中 count[k] 是 k 在样本中出现的次数。

计算以下统计量:

  • minimum:样本中的最小元素。
  • maximum:样本中的最大元素。
  • mean:样本的平均值,计算为所有元素的总和除以元素总数。
  • median
    • 如果样本有奇数个元素,那么中位数是排序后的中间元素。
    • 如果样本有偶数个元素,那么中位数是排序后两个中间元素的平均值。
  • mode:样本中出现次数最多的数字。保证是唯一的。

以浮点数数组 [minimum, maximum, mean, median, mode] 的形式返回样本的统计量。与实际答案误差在 10^-5 以内的答案都会被接受。

示例 1:

输入:count = [0,1,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
输出:[1.00000,3.00000,2.37500,2.50000,3.00000]
解释:count 表示的样本为 [1,2,2,2,3,3,3,3]。
最小值和最大值分别为 1 和 3。
平均值是 (1+2+2+2+3+3+3+3) / 8 = 19 / 8 = 2.375。
由于样本的大小是偶数,中位数是两个中间元素 2 和 3 的平均值,也就是 2.5。
众数是 3,因为它在样本中出现的次数最多。

示例 2:

输入:count = [0,4,3,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
输出:[1.00000,4.00000,2.18182,2.00000,1.00000]

约束条件:

  • count.length == 256
  • 0 <= count[i] <= 10^9
  • 1 <= sum(count) <= 10^9
  • count 所表示的样本的众数是唯一的。

解题思路

这道题目要求计算大样本的统计量,关键在于理解 count 数组的含义:count[i] 表示数字 i 在样本中出现的次数。

解题思路:

  1. 最小值和最大值:遍历 count 数组,找到第一个非零元素的索引作为最小值,最后一个非零元素的索引作为最大值。

  2. 平均值:计算总和除以总数量。总和 = Σ(i × count[i]),总数量 = Σcount[i]。

  3. 众数:遍历 count 数组,找到出现次数最多的数字。

  4. 中位数:这是最复杂的部分。需要找到排序后的第 n/2 和第 (n+1)/2 个元素(n为总元素个数)。

    • 如果总数为奇数,中位数是第 (n+1)/2 个元素
    • 如果总数为偶数,中位数是第 n/2 和第 n/2+1 个元素的平均值

对于中位数的计算,我们可以通过累加 count 数组来找到对应位置的元素。当累加和达到目标位置时,对应的索引就是我们要找的数字。

算法步骤:

  1. 一次遍历 count 数组,同时计算最小值、最大值、总和、总数量和众数
  2. 通过累加计数的方式找到中位数位置对应的元素值
  3. 根据总数量的奇偶性计算中位数

代码实现

class Solution {
public:
    vector<double> sampleStats(vector<int>& count) {
        int minimum = -1, maximum = -1, mode = 0;
        long long sum = 0, total = 0;
        int maxCount = 0;
        
        // 一次遍历计算基本统计量
        for (int i = 0; i < 256; i++) {
            if (count[i] > 0) {
                if (minimum == -1) minimum = i;
                maximum = i;
                sum += (long long)i * count[i];
                total += count[i];
                
                if (count[i] > maxCount) {
                    maxCount = count[i];
                    mode = i;
                }
            }
        }
        
        double mean = (double)sum / total;
        
        // 计算中位数
        double median;
        if (total % 2 == 1) {
            // 奇数个元素,找第 (total+1)/2 个元素
            long long target = total / 2 + 1;
            long long curr = 0;
            for (int i = 0; i < 256; i++) {
                curr += count[i];
                if (curr >= target) {
                    median = i;
                    break;
                }
            }
        } else {
            // 偶数个元素,找第 total/2 和第 total/2+1 个元素
            long long target1 = total / 2;
            long long target2 = total / 2 + 1;
            long long curr = 0;
            int val1 = 0, val2 = 0;
            
            for (int i = 0; i < 256; i++) {
                curr += count[i];
                if (curr >= target1 && val1 == 0) val1 = i;
                if (curr >= target2) {
                    val2 = i;
                    break;
                }
            }
            median = (val1 + val2) / 2.0;
        }
        
        return {(double)minimum, (double)maximum, mean, median, (double)mode};
    }
};
class Solution:
    def sampleStats(self, count: List[int]) -> List[float]:
        minimum = maximum = mode = -1
        total_sum = total_count = max_count = 0
        
        # 一次遍历计算基本统计量
        for i in range(256):
            if count[i] > 0:
                if minimum == -1:
                    minimum = i
                maximum = i
                total_sum += i * count[i]
                total_count += count[i]
                
                if count[i] > max_count:
                    max_count = count[i]
                    mode = i
        
        mean = total_sum / total_count
        
        # 计算中位数
        if total_count % 2 == 1:
            # 奇数个元素,找第 (total_count+1)/2 个元素
            target = total_count // 2 + 1
            curr = 0
            for i in range(256):
                curr += count[i]
                if curr >= target:
                    median = float(i)
                    break
        else:
            # 偶数个元素,找第 total_count/2 和第 total_count/2+1 个元素
            target1 = total_count // 2
            target2 = total_count // 2 + 1
            curr = 0
            val1 = val2 = 0
            
            for i in range(256):
                curr += count[i]
                if curr >= target1 and val1 == 0:
                    val1 = i
                if curr >= target2:
                    val2 = i
                    break
            median = (val1 + val2) / 2.0
        
        return [float(minimum), float(maximum), mean, median, float(mode)]
public class Solution {
    public double[] SampleStats(int[] count) {
        int minimum = -1, maximum = -1, mode = 0;
        long sum = 0, total = 0;
        int maxCount = 0;
        
        // 一次遍历计算基本统计量
        for (int i = 0; i < 256; i++) {
            if (count[i] > 0) {
                if (minimum == -1) minimum = i;
                maximum = i;
                sum += (long)i * count[i];
                total += count[i];
                
                if (count[i] > maxCount) {
                    maxCount = count[i];
                    mode = i;
                }
            }
        }
        
        double mean = (double)sum / total;
        
        // 计算中位数
        double median;
        if (total % 2 == 1) {
            // 奇数个元素,找第 (total+1)/2 个元素
            long target = total / 2 + 1;
            long curr = 0;
            for (int i = 0; i < 256; i++) {
                curr += count[i];
                if (curr >= target) {
                    median = i;
                    break;
                }
            }
        } else {
            // 偶数个元素,找第 total/2 和第 total/2+1 个元素
            long target1 = total / 2;
            long target2 = total / 2 + 1;
            long curr = 0;
            int val1 = 0, val2 = 0;
            
            for (int i = 0; i < 256; i++) {
                curr += count[i];
                if (curr >= target1 && val1 == 0) val1 = i;
                if (curr >= target2) {
                    val2 = i;
                    break;
                }
            }
            median = (val1 + val2) / 2.0;
        }
        
        return new double[] { minimum, maximum, mean, median, mode };
    }
}
/**
 * @param {number[]} count
 * @return {number[]}
 */
var sampleStats = function(count) {
    let min = -1, max = -1;
    let total = 0, sum = 0;
    let maxCount = 0, mode = 0;
    
    // Find min, max, total count, sum, and mode
    for (let i = 0; i < 256; i++) {
        if (count[i] > 0) {
            if (min === -1) min = i;
            max = i;
            total += count[i];
            sum += i * count[i];
            if (count[i] > maxCount) {
                maxCount = count[i];
                mode = i;
            }
        }
    }
    
    let mean = sum / total;
    
    // Find median
    let median;
    let mid1 = Math.floor((total - 1) / 2);
    let mid2 = Math.floor(total / 2);
    
    let currCount = 0;
    let median1 = -1, median2 = -1;
    
    for (let i = 0; i < 256; i++) {
        if (count[i] > 0) {
            let nextCount = currCount + count[i];
            
            if (median1 === -1 && mid1 < nextCount) {
                median1 = i;
            }
            if (median2 === -1 && mid2 < nextCount) {
                median2 = i;
            }
            
            if (median1 !== -1 && median2 !== -1) break;
            currCount = nextCount;
        }
    }
    
    median = (median1 + median2) / 2;
    
    return [min, max, mean, median, mode];
};

复杂度分析

复杂度类型复杂度
时间复杂度O(1)
空间复杂度O(1)

说明:

  • 时间复杂度:O(1),因为数组长度固定为 256,所以遍历次数是常数
  • 空间复杂度:O(1),只使用了常数个额外变量