LeetCode:382 Linked List Random Node蓄水池抽样算法

问题定义

长度为N的链表,N很大,但是不知道具体有多大。从N个元素中随机取出K个元素,只能遍历一次链表。用到的算法保证取出的元素恰好有K个,且他们是完全随机的(出现概率均相等)。

求解

该算法是针对从一个序列中随机抽取不重复的K个数,保证每个数被抽取到的概率为k/n这个问题而构建的。做法是:
首先构建一个可放K个元素的蓄水池,将序列的前K个元素放入蓄水池中。然后从第K+1个元素开始,以K/n的概率来决定该元素是否被替换到池子中,当遍历完所有元素之后,就可以得到随机挑选出的K个元素。复杂度为O(n)
其伪代码如下:
Init : a reservor(蓄水池) with the size:K
for i = k+1 to N
M = random(1,i);
if(M < K)
SWAP the Mth value and ith value
end for

证明


1.对于第i个数(i <K,在前K步被选中的概率是1,从第一步开始,i不被选中的概率为K/K+1,那么读到第n个数时,第i个数(i < k)被选中的概率 = 被选中的概率* 以后每一步不被换走的概率,即:1  * K/K+1 *  k+1/K+2  *……*n-1/n = K/n
2.对于第j个数(j>=K)被选中的概率为:在他出现时被选中的概率 * 在他出现以后不被换走的概率,即:
K/j * j/j+1 *……* n-1/n = K/n
3.综上得证


题目

Given a singly linked list, return a random node’s value from the linked list. Each node must have the same probability of being chosen.  Follow up:  What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?

实现:

import java.util.Random; public class Solution {      
private Random mRandom;    
 private ListNode head;    
 public Solution(ListNode head) {         
this.head=head;    
 }      /**      *蓄水池抽样算法      */     
public int getRandom() {         
mRandom=new Random();        
 int pos = 1;        
 ListNode node = head;         
ListNode res = head;          
while(node != null) {           
  //一直取最末尾的一个数            
 if (mRandom.nextInt(pos) == (pos-1)) {                
 res = node;//此处不可直接return。取第一个值的时候概率是百分之百,直接返回。             
}             
pos = pos+1;             
node = node.next;        
 }          
return res == null ? head.val : res.val;     
}      /**      *先获取长度再取随机值的方法      */     
public int getRandomXX() {       
  int randomVaule = mRandom.nextInt(this.getLength());         
int pos = 0;         ListNode res = head;         
while(res != null) {            
 if(pos == randomVaule) {                 
return res.val;             
}             
 res = res.next;             
pos++;         
}         
return res.val;   
  }     
 public int getLength() {         int len = 0;         ListNode node = head;         while(node != null) {           
  len++;             node = node.next;        
 }         
return len;   
  }  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值