day 4:2028. 找出缺失的观测数据

Leetcode 2028. 找出缺失的观测数据

现有一份 n + m 次投掷单个** 六面** 骰子的观测数据,骰子的每个面从 1 到 6 编号。观测数据中缺失了 n 份,你手上只拿到剩余 m 次投掷的数据。幸好你有之前计算过的这 n + m 次投掷数据的 平均值

给你一个长度为 m 的整数数组 rolls ,其中 rollsi 是第 i 次观测的值。同时给你两个整数 mean 和 n 。

返回一个长度为_ n 的数组,包含所有缺失的观测数据,且满足这 n + m 次投掷的 平均值 _mean 。如果存在多组符合要求的答案,只需要返回其中任意一组即可。如果不存在答案,返回一个空数组。

k 个数字的 平均值 为这些数字求和后再除以 k 。

注意 mean 是一个整数,所以 n + m 次投掷的总和需要被 n + m 整除。

已知部分数据、平均值即数据量大小,求平均值。那么就可以得到未知数据的总和。

java 复制代码
int m = rolls.length;
int sum = 0;
for (int i = 0 ; i < m; i++) {
    sum += rolls[i];
}

int rest = (m + n) * mean - sum;

需要判断得到的 rest 是否符合要求,不符合要求就直接返回 null 或一个长度为 0 的数组。

java 复制代码
if (rest < n || rest > (n * 6)) return new int[0];

那么就是知道位置数组的总和的数据量大小,只需要返回其中一个结果。

  • 贪心法,让前面的数据尽可能大,或者让前面的数据尽可能小,这两种实现类似。
  • 平均法,让数组数据保持一个平均值。
  • 随机法,真的每次获取一个随机数,但是要记得保证。

贪心法:

java 复制代码
// 代码 1 
for (int i = 0; i < n - 1; i++) {
    int num = 6;
    while ((rest - num) < (n - i - 1)) num--;
    res[i] = num;
    rest -= num;
}
res[n - 1] = rest;

// 代码 2
int num = 6;
for (int i = 0; i < n - 1; i++) {
    while ((rest - num) < (n - i - 1)) num--;
    res[i] = num;
    rest -= num;
}
res[n - 1] = rest;

比较一下代码 1 和 代码 2 的区别,就是局部变量的位置,一个在作用域包括 for 循环外,一个只作用在循环内。

后者需要在判断一次之前已经判断过的情况,因此会导致重复的计算浪费实现。

结果证明其时间有 6ms 变为了 3ms。

上述是让前面的数据尽可能大。如果想让前面的数据尽可能小,只要让 num 从 1 开始,修改 while 的条件为 while((res - num) > ((n - i - 1) * 6)) num++;即可。

平均法:

java 复制代码
int num = rest / n;
for (int i = 0; i < n - 1; i++) {
    while ((rest - num) > ((n - i - 1) * 6)) num++;
    res[i] = num;
    rest -= num;
}
res[n - 1] = rest;

这种方式还是逃不掉 for 循环判断剩余的能否放下。效率还是一样的。

随机法:

java 复制代码
Random random = new Random();
for (int i = 0; i < n - 1; i++) {
    int num = random.nextInt(5) + 1;
    while (((rest - num) < (n - i - 1)) || ((rest - num) > ((n - i - 1) * 6))) {
        num = random.nextInt(5) + 1;
    }
    res[i] = num;
    rest -= num;
}
res[n - 1] = rest;

哈哈,非常浪费时间,在一些特殊情况下,即结果都为 1 或都为 6,可能永远也取不到想要的值。

完整代码

java 复制代码
class Solution {
    public int[] missingRolls(int[] rolls, int mean, int n) {
        int m = rolls.length;
        int sum = 0;
        for (int i = 0 ; i < m; i++) {
            sum += rolls[i];
        }

        int rest = (m + n) * mean - sum;
        if (rest < n || rest > (n * 6)) return new int[0];
        int res[] = new int[n];
        int num = 6;
        for (int i = 0; i < n - 1; i++) {
            while ((rest - num) < (n - i - 1)) num--;
            res[i] = num;
            rest -= num;
        }
        res[n - 1] = rest;
        return res;
    }
}
相关推荐
代码雕刻家2 分钟前
编程语法细节
java·c语言·开发语言
SimonKing5 分钟前
Agnes AI出桌面版了,可图可视频,免费用
java·后端·程序员
左左右右左右摇晃24 分钟前
手写Tomcat原理整理
java·开发语言·笔记·tomcat
孫治AllenSun28 分钟前
【JVM】四大引用类型分析
java·开发语言·jvm
于慨30 分钟前
安装java
java
夕除31 分钟前
sign 是什么
java·前端
Penina10181 小时前
代码如何导入idea
java·intellij idea
.Hypocritical.1 小时前
Maven笔记——2
java·笔记·maven
huohuopro1 小时前
手写 Tomcat 步骤教程
java·网络
snow@li1 小时前
Java:Lombok 完整讲解
java