leetcode 382 Linked List Random Node

1 问题

给定一个单链表,随机返回一个节点的值,保证每个节点被选择的概率相同。

链表的长度未知,可能会非常大。

2 测试方法

一个节点数为7的单链表,返回1000000次值,统计每个节点被选择的频率。看每个节点被选择的频率是不是接近1/7。

3 java随机数生成类java.util.Random

Random(),创建一个新的随机数生成器。

int nextInt(int bound),生成的整数在[0, bound)之间,生成这个区间里面的每个int的概率相同。

nextInt(10),生成{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}这10个数中的一个,生成这10个数中的每个数的概率相同。

 

4 reservoir sampling,水塘抽样

这是一个在大数据流中随机抽样的问题,即在内存无法加载全部数据时,如何从未知大小的数据流中随机选取k个数据,保证每个数据被选择到的概率相同。

水塘抽样的具体操作:

第一,保留前k个数据;

第二,当遍历到第i个数据的时候,以k/i的概率保留该数据,同时随机删除前k个数据中的一个。

用归纳法证明:

当数据总数为k的时候,每个数据被抽到的概率为1,显然是相同的。

当数据总数为k+1的时候,当新加的第k+1的数据被以k/(k+1)的概率被选中的时候。原来的k个数据被选中的概率为:

1/(k+1) + (k/(k+1))*(1-1/k))=k/(k+1)

当数据总数为k+2的时候,当新加的第k+2的数据被以k/(k+2)的概率被选中的时候。原来的k+1个数据被选中的概率为:

(k/(k+1)) * (2/(k+2) + k/(k+2) * (1-1/k))=k/(k+2)

假设当数据总数为N的时候,按照水塘操作每个元素被选中的概率为k/N,那么当新来了一个新的元素N+1的时候,该元素被选中的概率为k/(N+1),其它元素被选中的概率为

(k/N)*(1 - k/(N+1) + k/(N+1)*(1 - 1/k))=k/(N+1)

所以,当数据总数为N+1的时候,所有数据被选中的概率也是一样的。

因此,水塘操作可以保证数据流中每个元素被选中的概率相同。

5 当k=1的时候就是Linked List Random Node问题

第一,保留第一个数据;

第二,当遍历到第i个数据的时候,以1/i的概率保留该数据用来替换原来的数据。

 

比如来了第4个数据,前三个数据被选中的概率是

在上个数据到来时被选中的概率 * 第4个数据没有被选中的概率 = (1/3) * (3/4) = 1/4

6 编码实现

private static int getRandomNode(ListNode head) {
int i = 1;
ListNode listNode = head;
int x = 0;
Random random = new Random();
while (listNode != null) {
if (random.nextInt(i) == (i - 1)) {
x = listNode.get();
}

listNode = listNode.next;
i++;
}

return x;
}

7 测试

HashMap<Integer, Integer> choosenCntMap = new HashMap<Integer, Integer>();

for (int j = 0; j < 1000000; j++) {
int x = getRandomNode(head);
if (choosenCntMap.containsKey(x)) {
int cnt = choosenCntMap.get(x);
cnt++;
choosenCntMap.put(x, cnt);
} else {
choosenCntMap.put(x, 1);
}
}

for (Integer x : choosenCntMap.keySet()) {

int cnt = choosenCntMap.get(x);

System.out.println("x:" + x + "----" + "cnt:" + cnt);
}

 

x:2----cnt:142675
x:3----cnt:142428
x:5----cnt:142322
x:7----cnt:143076
x:8----cnt:143200
x:10----cnt:143340
x:11----cnt:142959

 

每个节点被选择的概率都接近1/7。

 

 

10 参考资料

10.1 https://zhanghuimeng.github.io/post/leetcode-382-linked-list-random-node/

10.2 https://gregable.com/2007/10/reservoir-sampling.html

10.3 https://leetcode.com/problems/linked-list-random-node/discuss/85659/Brief-explanation-for-Reservoir-Sampling

 

转载于:https://www.cnblogs.com/hustdc/p/10948151.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值