题目描述 前往leetcode1093题
我们对 0 到 255 之间的整数进行采样,并将结果存储在数组 count 中:count[k] 就是整数 k 在样本中出现的次数。
计算以下统计数据:
minimum :样本中的最小元素。
maximum :样品中的最大元素。
mean :样本的平均值,计算为所有元素的总和除以元素总数。
median :
如果样本的元素个数是奇数,那么一旦样本排序后,中位数 median 就是中间的元素。
如果样本中有偶数个元素,那么中位数median 就是样本排序后中间两个元素的平均值。
mode :样本中出现次数最多的数字。保众数是 唯一 的。
以浮点数数组的形式返回样本的统计信息 [minimum, maximum, mean, median, mode] 。与真实答案误差在 10-5 内的答案都可以通过。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/statistics-from-a-large-sample
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
- 恢复原数据:我的办法是利用ArrayList tmp恢复原始数据,并利用tmp进行数据计算
public double[] sampleStats(int[] count) {
double[] res = new double[5];
int max = -1;
int index = 0;
// 用来恢复原始数据
ArrayList<Integer> tmp = new ArrayList<>();
for(int i = 0; i< count.length; i++){
if(count[i] > max){
max = count[i];
index = i;
}
for(int j = 0; j< count[i];j++){
tmp.add(i);
}
}
int len = tmp.size();
// 统计数据
res[0] = tmp.get(0);
res[1] = tmp.get(len-1);
res[2] = tmp.stream().mapToInt(Integer::intValue).sum() * 1.0/len;
res[3] = len%2==0 ? (tmp.get(len/2) + tmp.get((len/2)-1))*1.0/2 : tmp.get(len/2);
res[4] = index;
return res;
}
但是提交代码时报错,提示超出内存限制
2. 优化代码
- 使用多个单独的变量而不是数组,并且只在必要时分配它们,以减少内存使用;
- 通过直接在循环中跟踪最大值、最小值、总和、总计数等信息,从而避免多次操作数组;
- 将寻找中位数的计算移到单独的方法中,以使主方法更加简洁和易读。
public double[] sampleStats(int[] count) {
int max = -1, min = -1;
double sum = 0.0;
int totalCount = 0;
int mode = 0, modeCount = 0;
for (int i = 0; i < count.length; i++) {
if (count[i] != 0) {
if (min == -1) {
min = i;
}
max = i;
totalCount += count[i];
sum += i * count[i];
if (count[i] > modeCount) {
modeCount = count[i];
mode = i;
}
}
}
return new double[]{ min, max, sum / totalCount,
totalCount % 2 == 0 ? (findKthNumber(count, totalCount / 2) + findKthNumber(count, totalCount / 2 - 1)) / 2.0 : findKthNumber(count, totalCount / 2),
mode };
}
private int findKthNumber(int[] count, int k) {
int totalCount = 0;
for (int i = 0; i < count.length; i++) {
totalCount += count[i];
if (totalCount > k) {
return i;
}
}
return -1;
}
接下来 提交代码, 又错了!!!调试时发现平均值竟然出现了负数!!
分析原因:正数相乘得到负数是由于计算机内部数据类型的限制,造成数值溢出并被强制转换为负数所导致的结果(知道这个概念,可是使用过程中没遇到过此类问题,这是第一次,好吧 我是小白菜~)
解决办法:将操作数强制转换为long类型,在进行相乘操作时,会优先按照long类型进行计算,然后将结果再强制转换回int类型。这样可以避免数值溢出,从而得到正确的结果。
修改代码sum += i * count[i];
为 sum += (long) i * count[i];
最终代码如下:
public double[] sampleStats(int[] count) {
int max = -1, min = -1;
double sum = 0.0;
int totalCount = 0;
int mode = 0, modeCount = 0;
for (int i = 0; i < count.length; i++) {
if (count[i] != 0) {
if (min == -1) {
min = i;
}
max = i;
totalCount += count[i];
sum += (long) i * count[i];
if (count[i] > modeCount) {
modeCount = count[i];
mode = i;
}
}
}
return new double[]{ min, max, sum / totalCount,
totalCount % 2 == 0 ? (findKthNumber(count, totalCount / 2) + findKthNumber(count, totalCount / 2 - 1)) / 2.0 : findKthNumber(count, totalCount / 2),
mode };
}
private int findKthNumber(int[] count, int k) {
int totalCount = 0;
for (int i = 0; i < count.length; i++) {
totalCount += count[i];
if (totalCount > k) {
return i;
}
}
return -1;
}
最后成功啦!
ps:工作后很久没有刷题了,今天登录看了一下手痒痒便做了起来,整个过程还是很生涩的, Java中ArrryList的各种操作都想不起来了,以为要做很久,没想到一个小时就解决了(有点超出我的预期),由于思维变慢,解题过程中不能规避可能会遇到的问题,只能通过提交代码来一次次尝试,希望以后不断的积累来提升自己。