August 21, 2016 - algorithm

382. Linked List Random Node

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();

1. Analyse

It is a typical problem call “Reservoir Sampling”. If the length of array is N, the procedure of “Reservoir Sampling Algorhtm” is:

1.	Pick the 1st element as the result.
2.	1/2 possibility to change the result to be the 2nd element.
3.	1/3 possibility to change the result to be the 3rd element.
4.	1/4 possibility to change the result to be the 4th element.
...
N.	1/N possibility to change the result to be the Nth element.

The possibility of each element is:

1st:	1*(1-1/2)*(1-1/3)*(1-1/4)*...*(1-1/N) = 1/N
2nd:	1 * 1/2 * (1-1/3)*(1-1/4)*...*(1-1/N) = 1/N
3rd:	1*(1-1/2) * 1/3 * (1-1/4)*...*(1-1/N) + 1*1/2 * 1/3 * (1-1/4)*...*(1-1/N)
		= [ 1*(1-1/2) + 1*1/2 ] * 1/3 * (1-1/4)*...*(1-1/N)
		= 1/N
4th:	= 1/N
...
Nth		= 1/N

2. AC code

(21 Lines)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    /** @param head The linked list's head.
        Note that the head is guaranteed to be not null, so it contains at least one node. */
	ListNode *head;
    Solution(ListNode* head) {	
		srand(time(NULL));
        this->head = head;
    }
    
    /** Returns a random node's value. */
    int getRandom() {
		ListNode* p_node = this->head;
		int ans;
		int count = 1;
		while( p_node ){
			if( rand() % count++ == 0 )
				ans = p_node->val;
			p_node = p_node->next;
		}
		return ans;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(head);
 * int param_1 = obj.getRandom();
 */