我的一位前学生给我发了一条关于他在申请初级开发人员工作时遇到的面试问题的消息。
在模拟教室选举中,有两名候选人竞选总统。考虑到选民的两个百分比,找出课堂上可能选民的数量最少。
示例:
输入:50.00,50.00
输出:2输入:25.00,75.00
输出:4输入:53.23,46.77
输出:124 //第一个值,1138错了。感谢Loïc的正确值注意:输入百分比的总和始终为100.00%,小数点后两位
最后一个例子让我挠头。这是我第一次听说这个问题,而且我对如何解决这个问题感到很难过。
编辑:我打电话给我的学生解决了这个问题,并告诉我他不确定最后一个值。他说,我引用,“这是一个荒谬的大数字输出”:(对不起!我应该在网上发布之前研究更多〜我猜9,797是最后一个例子的输出虽然..答案 0 :(得分:8)
您可以使用选民百分比的best rational approximations来计算这些值。维基百科描述了如何从continued fraction获取这些值(可以使用euclidean algorithm计算这些值)。期望的结果是第一个近似值,其在预期值的0.005%之内。
以下是53.23%的例子:
10000 = 1 * 5323 + 4677
5323 = 1 * 4677 + 646
4677 = 7 * 646 + 155
646 = 4 * 155 + 26
155 = 5 * 26 + 25
26 = 1 * 25 + 1
25 = 25* 1 + 0
Approximations:
1: 1 / 1
-> 1 = 100%
2: 1 / (1 + 1/1)
-> 1/2 = 50%
2.5: 1 / (1 + 1 / (1 + 1/6))
-> 7/1 = 53.75%
3: 1 / (1 + 1 / (1 + 1/7))
-> 8/15 = 53.33%
3.5: 1 / (1 + 1 / (1 + 1 / (7 + 1/3)))
-> 25/47 = 53.19%
4: 1 / (1 + 1 / (1 + 1 / (7 + 1/4)))
-> 33/62 = 53.23%
我们在第3和第4个收敛点之前有额外值的原因是它们的最后一个项(分别为7和4)大于1,因此我们必须测试近似值,并减去最后一个项。
所需的结果是第一个值的分母,它绕到所需的值,在这个花瓶中是62.
答案 1 :(得分:4)
首先你可以注意到一个简单的解决方案是拥有10,000名选民。现在让我们尝试找一些比这更低的东西。
For each value of N starting à 1
For Each value of i starting à 1
If i/N = 46.77
return N
始终选择两个百分比中的最小值更快。
或更快:
For each value of N starting à 1
i = floor(N*46.77/100)
For j = i or i+1
If round(j/N) = 46.77 and round((N-j)/N) = 53.23
return N
<小时/> 对于第三个例子:
但
不能是1138 ......
但62正在发挥作用:
圆润它给你很好的价值。
答案 2 :(得分:2)
(经过一些广泛的编辑:)
如果你只有2名选民,那么你只能为候选人A和B产生以下百分比:
0+100, 100+0, or 50+50
如果你有3个选民,那么你有
0+100, 100+0, 33.33+66.67, 66.67+33.33 [notice the rounding]
所以这是一个关于分数的有趣问题。
如果你可以赚25%那么你必须至少有4个人(所以你可以做到1/4,因为1/2和1/3不会削减它)。您可以使用更多(即2/8 = 25%),但问题要求最少。
然而,更有趣的分数需要分子中大于1的数字:
2/5 = 40%
因为除了分子中的2个或更多之外你不能得到它(1 / x永远不会削减它)。
您可以在每一步进行比较并增加分子或分母,这比在j的整个样本空间上迭代然后递增i更有效;
即。如果你有3%的百分比,在96/99,97 / 99,98 / 99之前检查解决方案,甚至到x / 100之前是浪费时间。相反,您可以根据当前猜测的效果(大于或小于)来递增分子或分母
int max = 5000; //we only need to go half-way at most.
public int minVoters (double onePercentage) {
double checkPercentage = onePercentage;
if (onePercentage > 50.0)
checkPercentage = 100-onePercentage; //get the smaller percentage value
double i=1;
double j=1; //arguments of Math.round must be double or float
double temp = 0;
while (j<max || i<max-1) { //we can go all the way to 4999/5000 for the lesser value
temp = (i/j)*100;
temp = Math.round(temp);
temp = temp/100;
if (temp == checkPercentage)
return j;
else if (temp > checkPercentage) //we passed up our value and need to increase the denominator
j++;
else if (temp < checkPercentage) //we are too low and increase the numerator
i++;
}
return 0; //no such solution
}
找到可以产生55%的分母的逐步示例
55/100 = 11/20
100-55 = 45 = 9/20 (checkPercentage will be 45.0)
1/1 100.0%
1/2 50.00%
1/3 33.33%
2/3 66.67%
2/4 50.00%
2/5 40.00%
3/5 60.00%
3/6 50.00%
3/7 42.86% (too low, increase numerator)
4/7 57.14% (too high, increase denominator)
4/8 50.00%
4/9 44.44%
5/9 55.56%
5/10 50.00%
5/11 45.45%
6/11 54.54%
6/12 50.00%
6/13 46.15%
6/14 42.86%
7/14 50.00%
7/15 46.67%
7/16 43.75%
8/16 50.00%
8/17 47.06%
8/19 42.11%
9/19 47.37%
9/20 45.00% <-bingo
这种方法的好处在于它只需要(i + j)步骤,其中 i 是分子, j 是分母。
答案 3 :(得分:0)
我无法看到这个问题与初级开发人员的相关性。
答案 4 :(得分:0)
然后回答说,跳进我的脑袋更像是一种蛮力的方法。最多可以有5001个唯一答案,因为在00.00和50.00之间有5001个唯一数字。因此,为什么不创建和保存查找表。显然,不会有5001个独特的答案,因为会重复一些答案。关键是,只有5001个有效分数,因为我们四舍五入到两位数。
int[] minPossible = new int[5001];
int numSolutionsFound = 0;
N = 2;
while(numSolutionsFound < 5001) {
for(int i = 0 ; i <= N/2 ; i++) {
//compute i/N
//see if the corresponding table entry is set
//if not write N there and increment numSolutionsFound
}
N++;
}
//Save answer here
现在解决方案只是查表。
FWIW我意识到欧几里得解决方案是“正确的”。但我从来没有想过那次中期采访。但是,我知道这样的事情是可能的 - 但我不能当场鞭打它。