题目:
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:
常规思路遍历整个list,记录下长度然后生成随机数来确定选哪个Node,遍历到那个Node即可。但是要对list进行两次遍历。
代码1:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
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) {
root=head;
while(head)
{
size++;
head=head->next;
}
}
/** Returns a random node's value. */
int getRandom() {
ListNode* temp=root;
int index=rand()%size;
while(index)
{
index--;
temp=temp->next;
}
return temp->val;
}
private:
ListNode* root;
int size=0;
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(head);
* int param_1 = obj->getRandom();
*/
思路2:
Follow up中问了如果list很长无法知道length怎么办。这里使用蓄水池算法,其实是之前一种shuffle方式的升级,本质是能够从n个数中随机取出m个数,步骤如下:
首先构建一个m大小的数组,这就是最初的池子,把list中的前m个数放入数组。
建立一个整数ran,大小为m+1,生成随机数[0, ran]之间,如果随机数在[0, m-1]内,即在池子内,就把当前数和池内对应数swap。
每一轮都增大ran,并且node往下遍历,直到整个list遍历结束。
假设池子大小为1,[a],然后下一个是b。那么只要保证50%是a,50%是b即可。
假设池子大小为2,[a,b],然后下一个是c。那么只要保证a,b,c都是1/3。即池子的概率是2/3,下一个数概率是1/3。
假设池子大小为2,[a,b,c],然后下一个是d。那么只要保证a,b,c,d都是1/4。即池子的概率是3/4,下一个数概率是1/4。
这题就是池子大小为1时的情况,因此只要用一个整数来替代池子即可。如果随机数为0,则把当前数和池子中的数交换。
代码2:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
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) {
root=head;
}
/** Returns a random node's value. */
int getRandom() {
ListNode* temp=root;
int pool=temp->val;
temp=temp->next;
for(int ran=2; temp;ran++)
{
if(rand()%ran==0)
pool=temp->val;
temp=temp->next;
}
return pool;
}
private:
ListNode* root;
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(head);
* int param_1 = obj->getRandom();
*/
Reference: https://xujimmy.com/2017/10/15/shuffle.html