LeetCode 470题的要求是使用一个已有的rand7()
函数来实现一个rand10()
函数。rand7()
函数可以等概率地生成1到7之间的整数,而我们需要设计一个rand10()
函数来等概率地生成1到10之间的整数。
思路分析
直接使用rand7()
生成1到10之间的数是有挑战的,因为7和10不是倍数关系。我们可以通过以下步骤来实现:
-
扩展范围:首先,我们可以通过调用两次
rand7()
来生成一个更大的范围。具体来说,我们可以生成一个1到49的均匀分布。- 设
x = rand7()
,y = rand7()
,则可以构造一个数z = (x - 1) * 7 + y
,这样z
的范围是1到49。
- 设
- 拒绝采样:由于我们需要的是1到10的数,我们可以利用1到49的范围,但需要排除掉一些数。具体来说,如果生成的数在1到40之间,我们可以利用这个数来生成1到10的数;如果生成的数在41到49之间,则重新生成。
-
映射到1到10:对于在1到40之间的数,我们可以通过取模操作将其映射到1到10。具体来说,
z % 10 + 1
就可以得到一个1到10之间的数。
代码实现
以下是具体的代码实现:
def rand7():
这是一个假设的函数,实际实现依赖于具体环境
pass
def rand10(): while True:
生成1到49之间的数
x = rand7()
y = rand7()
z = (x - 1) * 7 + y
# 如果z在1到40之间,则接受这个数
if z <= 40:
return z % 10 + 1
# 如果z在41到49之间,重新生成
# 这里可以进一步优化,利用41到49之间的数来减少重新生成的概率
# 但为了简单起见,我们直接重新生成
详细解释
-
生成1到49的数:
x = rand7()
生成1到7之间的数。y = rand7()
生成1到7之间的数。z = (x - 1) * 7 + y
将x
和y
组合成一个1到49之间的数。这里(x - 1) * 7
将x
映射到0, 7, 14, 21, 28, 35, 42,再加上y
(1到7),得到1到49。
-
拒绝采样:
- 如果
z
在1到40之间,我们接受这个数。 - 如果
z
在41到49之间,我们重新生成,因为这部分数不能均匀映射到1到10。
- 如果
-
映射到1到10:
- 对于接受的数
z
,通过z % 10 + 1
将其映射到1到10。
- 对于接受的数
时间复杂度
虽然这个方法在最坏情况下可能需要多次调用rand7()
,但其期望时间复杂度是常数时间,因为每次重新生成的概率是逐渐减小的。
空间复杂度
这个方法的空间复杂度是O(1),因为只需要常数级别的额外空间。
通过这种方法,我们成功地将rand7()
转换为rand10()
,确保了生成的数的均匀性和随机性。
发表回复