題目描述:
給定一個單鏈表,隨機選擇鏈表的一個節點,並返回相應的節點值。保證每個節點被選的概率一樣。
進階:
如果鏈表十分大且長度未知,如何解決這個問題?你能否使用常數級空間複雜度實現?
思路:
蓄水池抽樣:(數學上可以證明,這裏不做證明)
從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個數中的一個數。