题目:
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
示例:
// 初始化一个单链表 [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);
// getRandom()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
solution.getRandom();
思路:这个题是蓄水池抽样问题,将相关的知识点补充在这里。原文链接:https://blog.csdn.net/huagong_adu/article/details/7619665
蓄水池抽样问题:从一个包含n个对象的列表S中随机选取k个对象,n为一个非常大或者不知道的值。通常情况下,n是一个非常大的值,大到无法一次性把所有列表S中的对象都放到内存中。我们这个问题是蓄水池抽样问题的一个特例,即k=1。
解法:我们总是选择第一个对象,以1/2的概率选择第二个,以1/3的概率选择第三个,以此类推,以1/m的概率选择第m个对象。当该过程结束时,每一个对象具有相同的选中概率,即1/n,证明如下。
证明:第m个对象最终被选中的概率P=选择m的概率*其后面所有对象不被选择的概率,即
虽然这个道理挺好理解的,但是地下这个代码还是不太懂。。。
nextInt()函数用于生产随机数,nextInt(n)用于生成一个范围在(0,n-1)之间的随机数。
代码:
class Solution {
private ListNode head;
/** @param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node. */
public Solution(ListNode head) {
this.head = head;
}
/** Returns a random node's value. */
public int getRandom() {
Random random = new Random();//一个随机数
int result = head.val;
ListNode currNode = head;
for(int i=1; currNode.next!=null; i++) {
currNode = currNode.next;
if((random.nextInt(i + 1)) == i) {//这块的意思可能是这个随机数可能是以1/i的概率去到i这个数,此时我们就对应的取出这
//个位置的节点
result = currNode.val;
}
}
return result;
}
}