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

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 整除。

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

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;
    }
}
相关推荐
linwq82 分钟前
设计模式学习(二)
java·学习·设计模式
桦说编程33 分钟前
CompletableFuture 超时功能有大坑!使用不当直接生产事故!
java·性能优化·函数式编程·并发编程
@_@哆啦A梦36 分钟前
Redis 基础命令
java·数据库·redis
Joyner20181 小时前
python-leetcode-从中序与后序遍历序列构造二叉树
算法·leetcode·职场和发展
因兹菜1 小时前
[LeetCode]day9 203.移除链表元素
算法·leetcode·链表
LNsupermali1 小时前
力扣257. 二叉树的所有路径(遍历思想解决)
算法·leetcode·职场和发展
雾月551 小时前
LeetCode LCR180文件组合
算法·leetcode·职场和发展
萌の鱼1 小时前
leetcode 2080. 区间内查询数字的频率
数据结构·c++·算法·leetcode
Tisfy1 小时前
LeetCode 0541.反转字符串 II:模拟
算法·leetcode·字符串·题解
字节全栈_rJF1 小时前
性能测试 —— Tomcat监控与调优:status页监控_tomcat 自带监控
java·tomcat