一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
题目描述
现有一份
n + m次投掷单个 六面 骰子的观测数据,骰子的每个面从1到6编号。观测数据中缺失了n份,你手上只拿到剩余m次投掷的数据。幸好你有之前计算过的这n + m次投掷数据的 平均值 。给你一个长度为
m的整数数组rolls,其中rolls[i]是第i次观测的值。同时给你两个整数ans和n。返回一个长度为
n的数组,包含所有缺失的观测数据,且满足这n + m次投掷的 平均值 是ans。如果存在多组符合要求的答案,只需要返回其中任意一组即可。如果不存在答案,返回一个空数组。
k个数字的 平均值 为这些数字求和后再除以k。注意
ans是一个整数,所以n + m次投掷的总和需要被n + m整除。
示例 1:
输入:rolls = [3,2,4,3], ans = 4, n = 2
输出:[6,6]
解释:所有 n + m 次投掷的平均值是 (3 + 2 + 4 + 3 + 6 + 6) / 6 = 4 。
示例 2:
输入:rolls = [1,5,6], ans = 3, n = 4
输出:[2,3,2,2]
解释:所有 n + m 次投掷的平均值是 (1 + 5 + 6 + 2 + 3 + 2 + 2) / 7 = 3 。
思路分析
首先利用测试用例搞清楚题目中的除法是指整除而非向下取整,然后看了下标签是数学模拟,没有用到任何dfs或者dp,最后一气呵成。(但是看标签习惯很不好,因为面试时候没有人告诉你这题是考察什么的)
贪心解法
1 计算总数,并且排除不能分配的情况 剩余待分配总数 大于可以分配的最大值并且最少每个位置可以分配一个 2 计算每个位置分配个数+多余轮分配的多一个
class Solution {
public:
vector<int> missingRolls(vector<int>& rolls, int ans, int n) {
int sum=accumulate(rolls.begin(),rolls.end(),0),m=rolls.size();
vector<int> ret;
int x=mean*(m+n);
if(x<sum+n||x>sum+6*n)//都取1或都取6,判断是否存在答案
return ret;
int y=x-sum;
while(n)//向其中添加剩余和的平均值
{
ret.push_back(y/n);
y=y-ret.back();
--n;
}
return ret;
}
};
模拟解法
分析一波:我们通过m次骰子的数字,得到了一个总数sum,再结合题目的均值ans,便可以知道剩余未知的n次骰子数字求和应该是dis = ans * (n+m) - sum。有了这个思路,做法便很明朗了,只需要求出dis的均值ans_n= (int)(dis / n)。然后从1~n个数字遍历,每个数字从ans _n到6遍历,找到n的求和为dis的话,直接返回。
class Solution {
public:
vector<int> missingRolls(vector<int>& rolls, int ans, int n) {
int temp=0;
for(int num:rolls){
temp+=(num-ans);
}
temp=mean*n-temp;
int key=temp/n;
int add=temp%n;
if(temp<n || temp>6*n){
return {};
}
vector<int>ans(n,key);
for(int i=0;i<add;i++){
ans[i]+=1;
}
return ans;
}
};