已有方法 rand7
可生成 1 到 7 范围内的均匀随机整数,试写一个方法 rand10
生成 1 到 10 范围内的均匀随机整数。
不要使用系统的 Math.random()
方法。
示例 1:
输入: 1 输出: [7]
示例 2:
输入: 2 输出: [8,4]
示例 3:
输入: 3 输出: [8,1,10]
提示:
rand7
已定义。- 传入参数:
n
表示rand10
的调用次数。
进阶:
rand7()
调用次数的 期望值 是多少 ?- 你能否尽量少调用
rand7()
?
思路:这道题自己确实是想不出来,只能借用网上的解法,所以这里借用博主的博客:https://blog.csdn.net/dyoyo90/article/details/12784861
如果由一个大的随机数产生一个小的随机数,比如rand10()要产生rand5(),那么可以用取余的操作,如果选出的随机数在1~5之间,那么保留,否则就继续重新选。
rand7->rand49
现在的问题是如何由一个小的随机数产生一个大的随机数,比如这道题的rand7()产生rand10(),那么我们先做这样的操作:res=7*(rand7()-1)+rand7(),这样res可以产生1~49的49个随机数,为什么呢?分解来看:7*(rand7()-1)可以产生0,7,14,21,28,35,42这7个数,那么在加上随机产生的1~7这7个随机数,就可以产生1~49这49个随机数。类似于先把数据的间隔拉大而能刚好进行本身的线性插值,这样就可以产生一个较大的随机数。
rand49->rand10
其实到这里已经很简单了,能产生1~49的数,那么我们只用随机到1~10的数即可,其余的数再重新随机取就行了。但是这样的复杂度有点高,相当于只保留了10(总49)的数据,时间复杂度为O(49/10)=O(4.9)。其实我们可以取1~40的数,然后再对取到的数取余操作即可,这样的复杂度为O(49/40)=O(1.225)。
参考代码:
class Solution {
public:
int rand10() {
int res;
do {
res = 7 * (rand7() - 1) + rand7();
} while (res > 40);
return res % 10 + 1;
}
};