Linked List Random Node

udpate Jul,29 2017 17:02

LeetCodearrow-up-right

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?

Example:

    // Init a singly linked list [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() should return either 1, 2, or 3 randomly.
    // Each element should have equal probability of returning.
    solution.getRandom();

Basic Idea:

这道题目涉及到了新的内容,和随机概率有关,这里需要说一下 Reservoir Sampling 的 strategy。 这里是leetcode discussion 中对于这个内容的说明arrow-up-right

Problem: Select K elements from n.

Choose 1, 2, 3, ..., k first and put them into the reservoir.
For k+1, pick it with a probability of k/(k+1), and randomly replace a number in the reservoir.
For k+i, pick it with a probability of k/(k+i), and randomly replace a number in the reservoir.
Repeat until k+i reaches n

解释:当我们要随机选择 k 个元素的时候,例如当前所visit的元素是第n个,我们需要保证它被选择的概率是 `k / n`,
  这也就是之前公式中 `k / (k + i)` 的来源。至于正确性,可以递推找规律,归纳证明。

具体地,在这里,k = 1. 所以每次我们只需要以 1/(i) 的概率选择是否将当前element替换已选择的元素即可。如果要在n个元素中选k个,则对于前k个元素直接加入res,之后对于第i个元素,以 k / i 的概率将其加入res,并随机选择一个res中的元素弹出即可。

  • 另:当然也可以遍历一遍,存好所有元素,然后用随机数生成index选择,只是说如果不可以使用extra space 这种方法就不可以了。

Java Code:

Python Code:

Using buffer, O(n) time for create buffer, O(1) for query. O(n) space.