LeetCode #382: Linked List Random Node
(Problem Link) 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.
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?
// 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();
Reservoir Sampling Sample size 1: Suppose we see a sequence of items, one at a time. We want to keep a single item in memory, and we want it to be selected at random from the sequence. If we know the total number of items (n), then the solution is easy: select an index i between 1 and n with equal probability, and keep the i-th element. The problem is that we do not always know n in advance. A possible solution is the following:
- Keep the first item in memory.
- When the i-th item arrives (for i>1):
- with probability 1/i, keep the new item instead of the current item; or equivalently
- with probability 1-1/i, keep the current item and discard the new item.
* when there is only one item, it is kept with probability 1;
* when there are 2 items, each of them is kept with probability 1/2;
* when there are 3 items, the third item is kept with probability 1/3, and each of the previous 2 items is also kept with probability (1/2)(1-1/3) = (1/2)(2/3) = 1/3;
* by induction, it is easy to prove that when there are n items, each item is kept with probability 1/n.
# Definition for singly-linked list. # class ListNode(object): # def __init__(self, x): # self.val = x # self.next = None class Solution(object): def __init__(self, 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. :type head: ListNode """ self.head = head def getRandom(self): """ Returns a random node's value. :rtype: int """ from random import randint p = self.head res = p.val i = 2 p = p.next while p: if randint(1, i) == 1: res = p.val p = p.next i += 1 return res # Your Solution object will be instantiated and called as such: # obj = Solution(head) # param_1 = obj.getRandom()