题目描述:
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
思路:
蓄水池抽样:(数学上可以证明,这里不做证明)
从N个数中抽取k个数,N很大,k个数被抽中概率一样。
方法:
- 先初始化一个集合,集合中有k个元素,将此集合作为蓄水池。
- 从第k+1个元素开始遍历,以概率是k/k+1换掉前k个数中的任意一个。
- 一直走下去,直到数据结束,最后存起来的k个数被抽中的概率一样。
from random import random
listz = [N个数]
list1 = [前k个数] # 前k的数的索引是[0,k-1]
for i in range(k to N): # 从第k+1个数开始遍历,i是索引
m = randint(1, i+1)
if( m < k) # k / (i+1)
list1[m],listz[i] = list1[m],listz[i]
代码实现(k=1):
class Solution(object):
def __init__(self, head):
self.head = head
def getRandom(self):
count, res = 1, self.head.val
cur = self.head.next
while cur:
if random.randint(1,count+1) <= 1:
res = cur.val
count, cur = count + 1, cur.next
return res
class Solution(object):
def __init__(self, head):
self.head = head
def getRandom(self):
count, res = 1, self.head.val
cur = self.head.next
while cur:
if random.random()*(count+1) <= 1:
res = cur.val
count, cur = count + 1, cur.next
return res
以上两个代码都可以,只要保证遍历到第i个数时,以概率k/i换掉前k个数中的一个数。