力扣470. 用 Rand7() 实现 Rand10()

问题概述

例如有一个函数 RandK() 它可以生成均匀分布在 [0, K) 的整数,问如何生成均匀分布在 [0, N)的整数

解决方案

该类型题的本质是 K进制逐位生成 + 拒绝采样 ,简单来说,若我们有一个 RandK() , 那么我们生成一个 n位的K进制数 ,我们通过 RandK() * K^ (n-1) 逐位生成 这个 【n位K进制数】,可以得到这个 【n位k进制数】的取值范围是 [0, k^n)即 [0, k^n - 1],并且这是均匀分布的

以 n = 3, k = 2 为例

n = 3n = 2n = 1
Rand2() * 2 * 2Rand2() * 2^1Rand2() * 2^0

那么也就是说,我们通过 RandK() 可以生成 [0, k^n) 间的数,那么我们可以取其中的 [0, N) 部分,就实现了 RandN() 的功能!也就是我们 【拒绝采样】 [N, k^n) 部分的数,当生成该区间的数时,就重新生成!

不过,为了减少 RandK() 被调用次数,我们可以取一个数 Num = N * max(i) ,{i = 1,2,3…} 说白了就是取小于 k^n 的 最大的 N 的倍数。然后 拒绝采用 [Num, k^n) 部分的数

实际问题

实际上,我们用 RandK 生成 RandN 时,需要区分 K > N 还是 K < N

对于 K > N:我们尝试将 K 拆解

简单来说,我们选取一个数 k ,它满足 K % k == 0 ,因为我们需要保证生成均匀分布在 [0, k) 的整数,这个 k 要比 N 小!

然后 再用 k 进行 k进制 逐位生成 + 拒绝采样即可! (注意,我们做这些是为了减少 randK 的调用次数

最简单的办法: 就是直接拒绝采样 [N, K) 的数就好了

所以 K > N 这个问题一般不会这样出… 只是考虑优化

对于 K < N : K进制逐位生成 + 拒绝采样

例题:470. 用 Rand7() 实现 Rand10()

func rand10() int {
    for {
        num := (rand7()-1) * 7 + (rand7() - 1) // 均匀生成 [0, 49)
        if num >= 0 && num < 40 {
            return num % 10 + 1
        }
    }
}

变形题:

有一个 RandP() , 它有 p% 的概率生成 1, 有 (100-p)% 的概率生成 0。然后用 RandP 实现 RandN ?

其实就是通过生成 (1, 0)、(0, 1) 是等概率的来模拟 Rand2() ,然后套娃即可

func Rand2() {
    for {
		num1, num2 := RandP(), RandP()
		if num1 + num 2 == 1 {
			if num1 == 1 {
				return 1
			} else {
				return 0
			}
		}
	}
}

func RandN() {
	...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值