问一道阿里的面试题如何求解

2020-02-17 10:17:08 +08:00
 dazhangpan

N 年前面试阿里的时候有一道算法题不会做,后来一直念念不忘,在网络搜了一下也没找到答案,至今仍然没想出来...

题目是给一个方法 foo(),能以各 50%的概率随机返回 0 或者 1。问题是基于 foo()方法,实现一个 boo()方法,该方法能以各 10%的概率返回[0-9]中的一个数字。

感觉对受过相关训练的同仁来说应该不难,无奈本人对算法不是太在行 o(╥﹏╥)o

9184 次点击
所在节点    程序员
67 条回复
newbie269
2020-02-17 18:28:24 +08:00
Knuth 算法?
loryyang
2020-02-17 20:22:26 +08:00
上面楼太多了,不知道是否提到一个问题,这些方案从理论上都无法控制最差 case 下的时间。比如 16 中组合,拿 10 组,那么 6/16=37.5%的概率会重试,那么重试两次有 0.375^2,重试 10 次有 0.375^10 的概率,虽然很低,但是理论上依然存在。你无法控制这个最差 case。
另外我在想是不是做排列的时候,可以再多做一次,变成 32 种组合,选 30,那么有 2/30 的概率重试,重试概率大大降低了,虽然每次多计算一次 foo,但是相比较于重试的概率,应该不会亏
简单算一下(默认就算前两次),排列四次,期望 4*10/16 + 8*6/16 = 5.5, 排列五次:5 * 30/32 + 10 * 2/32 = 5.3。第二种期望的计算会少一些
loryyang
2020-02-17 20:25:02 +08:00
哦,我看到我的想法 @Windsooon 已经提到了,整理的还是挺完整的。我查了些资料,应该这就是最好的解了。看起来面试官也是准备了后手的,你提出 16 组合解之后,他应该会追问你:你觉得这个方案还有什么问题吗?
soy
2020-02-17 21:19:58 +08:00
算 4 次得到二进制数 x,(0<=x<16)
如果 x<10 返回 x
如果 10<=x<15 可以将(x-10)*2 再运算一个奇偶位返回
如果 x=15 重新计算
期望值
exp = 4*10/16 + 5*5/16 + (exp+5)*1/16
exp = 4.6
ic2y
2020-02-17 22:02:15 +08:00
@dazhangpan

可以换一个思路,我认为这个题目,考察的内容,非常接近 RC4 的流式加密算法,有个文章链接:
https://www.cnblogs.com/gambler/p/9075415.html

题目中给出的 foo()函数 [产生 0-1 随机数] ,我们可以用来初始化 流式加密的 init 映射状态。随后的 随机数产生,可以完全不依赖 foo()函数,完全依靠流式加密的方式,产生概率 10%的 [0-9]

==============Java 代码如下==================

package com.ic2y;

public class RandomNumber {
private static int MAPPING_LEN = 10;
//映射 0-9 的 关系
private int[] mapping = new int[MAPPING_LEN];
private int i = 0;
private int j = 0;
public RandomNumber(){
//初始化 mapping,再进行打乱
for(int i = 0;i < 10;++i){
mapping[i] = i;
}
//shuffle 算法,
for ( int i = MAPPING_LEN; i > 0; i-- ){
swap(getRandomLessTen(), i - 1);
}
}

private int getRandomLessTen(){
int val;
do {
val = doGetRandomLessTen();
if(val < 10){
return val;
}
}while (true);
}

private int doGetRandomLessTen(){
int val = 0;
for(int i = 0;i <4;++i){
val = val * 2 + foo();
}
return val;
}

//已知的产生 0 1 随机数的 函数
private int foo(){
return (int)System.currentTimeMillis() % 2;
}

//外界调用 boo 产生 0-9 随机数
public int boo(){
i = (i + 1) % MAPPING_LEN;
j = (j + mapping[i]) % MAPPING_LEN;
swap(i,j);
return mapping[(mapping[i] + mapping[j]) % MAPPING_LEN];
}

private void swap(int l,int r){
int tmp = mapping[l];
mapping[l] = mapping[r];
mapping[r] = tmp;
}


public static void main(String[] args){
RandomNumber r = new RandomNumber();
int testNumber = 100000;
int[] f = new int[10];
for(int i = 0;i < testNumber;++i){
++f[r.boo()];
}

float fTestNumber = (float)testNumber;
for(int i = 0; i < 10;++i){
System.out.println(String.format("Num:%d Probability:%.2f count:%d",i,f[i] / fTestNumber,f[i]));
}

}
}

=======结果=======

Num:0 Probability:0.10 count:9863
Num:1 Probability:0.10 count:10051
Num:2 Probability:0.10 count:10054
Num:3 Probability:0.10 count:10024
Num:4 Probability:0.10 count:10031
Num:5 Probability:0.10 count:9942
Num:6 Probability:0.10 count:10007
Num:7 Probability:0.10 count:9877
Num:8 Probability:0.10 count:10083
Num:9 Probability:0.10 count:10068
wizardoz
2020-02-18 17:11:53 +08:00
@learnshare 你这算法还没做到 10%的概率
wizardoz
2020-02-18 17:14:17 +08:00
@learnshare 好吧我错了,没细看 1#答案

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/645168

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX