原理为蓄水池抽样:一个未知大小的数据流,随机返回k个数据,每个样本被选中的概率是相同的。所以可以直接读入的时候,随机返回。
证明呢?
数学归纳法
假设前
N
N
N条数据,返回
K
K
K条,每条被返回的概率相同,都是
K
N
\frac{K}{N}
NK。
那么
N
+
1
N+1
N+1条数据返回
K
K
K条的概率,用
K
N
+
1
\frac{K}{N+1}
N+1K的概率去选新增的第
K
+
1
K+1
K+1条,那么元素中被采样的概率为:
1、选中了新增的这一个,前N条中有一条被替换:
K
N
+
1
∗
K
−
1
K
∗
K
N
=
K
−
1
N
∗
K
N
+
1
\frac{K}{N+1}*\frac{K-1}{K}*\frac{K}{N}= \frac{K - 1}{N} * \frac{K}{N+1}
N+1K∗KK−1∗NK=NK−1∗N+1K
2、第
N
+
1
N+1
N+1条没有被选中:
(
1
−
K
N
+
1
)
∗
K
N
=
N
+
1
−
K
N
+
1
∗
K
N
(1 - \frac{K}{N+1}) * \frac{K}{N} = \frac{N + 1 - K}{N+1} * \frac{K}{N}
(1−N+1K)∗NK=N+1N+1−K∗NK
概率相加结果为:
K
N
+
1
\frac{K}{N+1}
N+1K
结果得证。
代码为:
random() 结果返回实数,范围在[0,1)之内。
class Solution:
def __init__(self, head: ListNode):
"""
@param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node.
"""
self.head = head
def getRandom(self) -> int:
"""
Returns a random node's value.
"""
count,res = 1,-1
from random import random
cur = self.head
while(cur):
if(int(random()*count) == 0):
res = cur.val
count, cur = count + 1, cur.next
return res