Leetcode 2028. 找出缺失的观测数据
现有一份 n + m 次投掷单个** 六面** 骰子的观测数据,骰子的每个面从 1 到 6 编号。观测数据中缺失了 n 份,你手上只拿到剩余 m 次投掷的数据。幸好你有之前计算过的这 n + m 次投掷数据的 平均值 。
给你一个长度为 m 的整数数组 rolls ,其中 rolls[i] 是第 i 次观测的值。同时给你两个整数 mean 和 n 。
返回一个长度为_ n 的数组,包含所有缺失的观测数据,且满足这 n + m 次投掷的 平均值 是 _mean 。如果存在多组符合要求的答案,只需要返回其中任意一组即可。如果不存在答案,返回一个空数组。
k 个数字的 平均值 为这些数字求和后再除以 k 。
注意 mean 是一个整数,所以 n + m 次投掷的总和需要被 n + m 整除。
已知部分数据、平均值即数据量大小,求平均值。那么就可以得到未知数据的总和。
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 的数组。
if (rest < n || rest > (n * 6)) return new int[0];
那么就是知道位置数组的总和的数据量大小,只需要返回其中一个结果。
- 贪心法,让前面的数据尽可能大,或者让前面的数据尽可能小,这两种实现类似。
- 平均法,让数组数据保持一个平均值。
- 随机法,真的每次获取一个随机数,但是要记得保证。
贪心法:
// 代码 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++;
即可。
平均法:
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 循环判断剩余的能否放下。效率还是一样的。
随机法:
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,可能永远也取不到想要的值。
完整代码
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;
}
}