382. 链表随机节点
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
示例:
// 初始化一个单链表 [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()方法应随机返回1,2,3中的一个,保证每个元素被返回的概率相等。
solution.getRandom();
解题思路: 本题最直接的解题方法是,首先获取链表的长度len,然后在[0,len)内获取一个随机值n,然后直接在链表上遍历n步即可得到随机节点。这个不涉及到什么特殊算法,比较直接。在进阶中提到链表长度未知,那么就不能获取链表长度了,这题需要利用蓄水池抽样算法解题,这里取蓄水池的大小为1,将初值置为head的值,然后按照蓄水池采样算法,每次取余的值为0时,则替换。
蓄水池采样算法:
在n个数中等概率取m个数,怎么取?
我们维持m大小的池子,
- 当接收第i个数时,i小于m,则直接放到池子中,
- 当i>=m时,则在[0,i]产生一个随机数d,若d落在[]0,m - 1]范围内,则用接收到的第i个数替换蓄水池中第d个数
- 反复2
[LeetCode] 382. Linked List Random Node 链表随机节点
/**
* 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. */
Solution(ListNode* head) {
this->head = head;
}
/** Returns a random node's value. */
int getRandom() {
int res = head->val;
ListNode *cur = head->next;
int i = 2;
while (cur) {
int val = rand() % i;
if (val == 0) res = cur->val;
++i;
cur = cur->next;
}
return res;
}
private:
ListNode *head;
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(head);
* int param_1 = obj->getRandom();
*/