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();
分析
这一题刚开始想法是直接用vector存放所有node的地址,然后以length作为抽样直接获取随机值,可以保证概率均等。
但是题目说如果链表的长度是不确定的,而且要求使用常数的内存空间。这个题目解法就需要利用蓄水池抽样的办法去解决。
这个算法我也是第一次接触,还是挺新颖的,主要可以用在流计算上面对输入流求随机值。这位同学的学习笔记应该非常清晰https://www.jianshu.com/p/a4ab07f5752e。应用到现在这道题上应该就是在一个长度位置的输入流中求1个随机的值。可以将蓄水池的大小设置为1,从前往后遍历,当第i个node计算出rand()%i == 0时,表明选中了第i个元素,直接与第一个替换即可。
Code
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. */
Solution(ListNode* head) {
mHead = head;
}
/** Returns a random node's value. */
int getRandom() {
ListNode* res = mHead;
ListNode* node = mHead;
int index = 1;
while(node)
{
if (rand()%index == 0)
res = node;
node = node->next;
index = index + 1;
}
return res->val;
}
ListNode* mHead;
};
运行效率
Runtime: 48 ms, faster than 26.37% of C++ online submissions for Linked List Random Node.
Memory Usage: 16.6 MB, less than 5.00% of C++ online submissions forLinked List Random Node.