LeetCode: Linked List Random Node
Another one from LeetCode: https://leetcode.com/problems/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?
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?
The solution here is very similar to a post about reading a random line from a file. The solution is linear and no extra space is needed. Basically have a counter starting at 0. Generate a number between between 0 and the counter, randomly. Whenever that number is 0, assign the current element to the return value. This is guaranteed to give you a fair choice of elements, assuming the random generator is statistically sound. Code is below, very short. Cheers, Marcelo.
public class Solution
{
private ListNode head = null;
private Random rd = new Random();
/** @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()
{
int count = 0;
int retVal = 0;
for (ListNode node = head; node != null; node = node.next)
{
if (rd.Next(0, ++count) == 0) retVal = node.val;
}
return retVal;
}
}
And again we have the same solution :) I guess it's not surprising, since it's just a special case of reservoir sampling, but what I like about this solution in particular is that it actually requires a bit of thinking to prove the correctness, since it's not enough to rely on tests.
ReplyDeleteAs always posting a C++ solution below:
class Solution {
private:
ListNode* head;
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. */
Solution(ListNode* head): head(head) {}
/** Returns a random node's value. */
int getRandom() {
ListNode* temp = head;
ListNode* random = nullptr;
for (int i = 0; temp != nullptr; ++i, temp = temp->next) {
int r = rand() % (i + 1);
if (r == 0) random = temp;
}
return random->val;
}
};