本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、题目描述:
1093. 大样本统计 - 力扣(LeetCode) (leetcode-cn.com)
我们对 0 到 255 之间的整数进行采样,并将结果存储在数组 count 中:count[k] 就是整数 k 在样本中出现的次数。
计算以下统计数据:
- minimum :样本中的最小元素。
- maximum :样品中的最大元素。
- mean :样本的平均值,计算为所有元素的总和除以元素总数。
- median :
- 如果样本的元素个数是奇数,那么一旦样本排序后,中位数 median 就是中间的元素。
- 如果样本中有偶数个元素,那么中位数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,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表示的样本为[1,1,1,1,2,2,3,3,3,4,4]。
最小值为1,最大值为4。
平均数是(1+1+1+1+2+2+2+3+3+4+4)/ 11 = 24 / 11 = 2.18181818…(为了显示,输出显示了整数2.18182)。
因为样本的大小是奇数,所以中值是中间元素2。
众数为1,因为它在样本中出现的次数最多。
提示:
- count.length == 256
- 0 <= count[i] <= 10^9
- 1 <= sum(count) <= 10^9
- count 的众数是 唯一 的
二、思路分析:
这是一个类似hash表的表示方法,如count[10]=5表示数字10出现了五次。
思路:
先正序找到第一个不为零的元素,此时count[i]>0,表示i元素出现过,因为是第一个找到的所以肯定是最小值。
同理倒序找到最大值。
然后扫描索引为最小值到最大值之间的数组,0-min,max-255都是0,不用管。 用变量cnt、sum分别记数字出现次数和数字总合,以及count[i]最大值与所对应的i。
扫描完之后一除就是平均数,上面记下的i是众数。
所有数字出现次数对2取余数,如果余1说明中位数只有一个,余0说明有两个取平均。 然后再次扫描,每次在cnt中减去count[i],当cnt<=count[i]时说明在当前i取到中位数。 两个中位数的的找法相同。
三、AC 代码:
typedef long long ll;
typedef double db;
class Solution {
public:
vector<double> sampleStats(vector<int>& count) {
int n=count.size();
ll sum=0;
int cnt=0,maxx=0,temp=0;
int half=-1,halfcount=0;
vector<int>res;
res.reserve(256);
for(int i=0;i<n;i++){
if(count[i]==0)continue;
res.push_back(i);
sum+=count[i]*i;
cnt+=count[i];
if(count[i]>temp){
temp=count[i];
maxx=i;
}
while(halfcount==0||cnt/2>halfcount){
half++;
halfcount+=count[res[half]];//halfcount表式的含义是拥有多少个数据
}
}
//下面是判断中位数的,因为上面的while操作,所以我们再进行中位数的判断会非常的容易。。。
db med;
if(cnt/2==halfcount){//这个表示的是,我们拥有偶数个数据
med=(db)0.5*(res[half]+res[half+1]);
}else{
med=(db)res[half];
}
vector<db>ans;
ans.push_back(1.0*res[0]);
ans.push_back(1.0*res.back());
ans.push_back(1.0*sum/cnt);
ans.push_back(med);
ans.push_back(1.0*maxx);
return ans;
}
};