今天给大家介绍一个有点小“意思”的题目,这个题目本身没有特别的技术难点,但是可以带大家怀念一下回到小学二年级学习平均数时候的数学课~
先上题目——【找出缺失的观测数据】:
乍一看,简单到爆炸好嘛——.
“这不就是给定一个数列和平均数,反推其中未知的几个数么?”小伙伴如是评价到。
没错,确实是这样的~
需要注意的点,题目中也已经加黑标出——“六面”、“平均值”。
“平均值”我们已理解,那么“六面”的意思就是本题唯一的限定条件了,即——
数列中的每个数的最大可能值为6。
这一下,格局就关闭了;
数列就收敛了;
世界就无趣了;
很明显这个题并不是一个算法题,而是一个解决 validation 【校验】的问题,
大家要解决的并不是如何算出数列中缺失的数字的排列组合,而是这些组合“不能”为哪些组合,从而排除掉~
要考验的是对输入边界的把控能力,这一点,但凡接收过产品需求的程序猿们来说,简直太简单了啊,我直接一个大B兜——
WTH?WTF?
我不李姐,我不承认。
果然LeetCode不同凡响,当它考你算法的时候,是真的考算法,不必控制输入边界;
当它考你输入边界的时候,真的是无视算法,专门在边界上绕弯弯~
代码如下——
class Solution {
public int[] missingRolls(int[] rolls, int mean, int n) {
int[] output = new int[n];
int[] nullOutput = new int[0];
int m = rolls.length;
int rollAggregate = 0;
int outputAggregate = 0;
for (int element : rolls){
rollAggregate += element;
}
int totalLeng = m + n;
int total = totalLeng * mean;
int remainder = total - rollAggregate;
#对【剩余未知元素之和】除以6,舍余
if (remainder / n <= 6) {
for (int i = 0; i < n; i++) {
#得到一个未知元素值
output[i] = remainder / (n - i);
#去掉刚得到的未知元素,把剩下的放回remainder
remainder -= output[i];
#若该未知元素大于6或者为负,直接i+n跳出循环
if (output[i] > 6 || output[i] <= 0) {
output = nullOutput;
i += n;
}
}
}
else
output = nullOutput;
return output;
}
}
“每个元素都要小于等于6”,本代码由此而生。
核心思想是:
1. 将平均数乘以数组中的元素个数,得到【所有元素之和】,
2. 用该合数减去【已知元素之和】,可得【未知元素之和】
3. 用【未知元素之和】除以【未知元素数量】,可得【每个未知元素的最平均值】”(稍后解释“最平均值”含义)
4. 若【每个未知元素的最平均值】大于6,说明这个平均值太大了,超出了给定的“未知元素个数 × 未知元素最平均值”的值,则可证该数组不存在;
5. 用【未知元素之和】减去【每个未知元素的最平均值】,得到【剩余未知元素之和】,依次循环,直到减到最后一个【未知元素】为止;
6. 反之,若【每个未知元素的最平均值】小于等于6,说明这个数组有救,我们也不必猜测所有可能的数组,反正题目也没要求,直接输出一个以【每个未知元素的最平均值】为基准的数组就可以了。
上面这个流程看不懂的话,可以看下面的手写稿~~
这里面提到的【每个未知元素的最平均值】是我个人的定义,大致可以理解为:
假设一个多边形,有 n 条边(题中体现为“n 个元素”),n 条边之和——即周长固定不变(在题中体现为“平均值 × n”)时,那么拉长其中一边,必然导致另外一个或数个边的缩短,易证:当每个边长度相等时,该多边形面积最大。
(好家伙,差点设计出个车标来……)
这个多边形面积最大时,每条相等的边的长度,便是【每个未知元素的最平均值】。比如等边三角形的三边长。
如果大家按照这个思路写代码,就会遇到一个“小问题”:上述5步中的第3步,做了一个除法,凡是除法就必须考虑余数的问题,而在我的代码中,余数是直接被舍弃的,直接取余。
这就会造成一个问题~
如果除完,得到的未知数字是“6.x”,那么这个 x 会直接被舍弃掉,但是我们题目要求是“不能超过6”,舍弃掉 x 的“6.x”却没被过滤掉,被当做了合理的值“6”带入后续运算,这就出事了。
我们得到的未知数字是“6.x”,假设有3个未知数字,那么前两个 x 积累下来的误差,就会全部累加到最后一个未知数字上,百分百导致最后一个数溢出(超过限制值:6)。
如果这时代码中没有检查每个元素的值的话,就过不了了……
好了,我们解决了超过6的数,就安全了么?
当然不是。
我们还得解决负数~
说到这,应该有同学已经秒懂了。
没错,我们的【未知元素之和】是减出来的,只要是减法就会涉及“负数”。
至于怎么解决负数,很简单,就跟增加“不许大于6”的条件一样,再加一个“不许为负”的条件好了~~
但是你在有限的15分钟内真的能从零想到这么多么?
我们马上回来。