以在线的方式从一个数据流中随机选出k个元素,注意点:
蓄水池抽样的典型应用场景如下:
解决方法:
先以随机选出1个结点为例,第一次抽样时,选中该结点的概率为1,第二次抽样时,有1/2的概率将第二次抽样的值作为选中的结点,第三次抽样时,选中的概率为1/3,以此类推,遍历完所有的结点,最后保留的结点就是符合要求的随机结点,以单链表为例,示例代码如下:
int getRandom(ListNode *head) { int ans; int i = 1; for(auto node = head; node != nullptr; node = node->next) { if(rand() % i == 0) { // 第i个结点选中的概率为1/i,如果命中 ans = node->val; } i++; } return ans; } |
接下来是随机选取m个结点,算法思路如下:
示例代码如下:
vector<int> getRandom(ListNode *node, int m) { vector<int> pool(m); int i = 0; while(i < m && node != nullptr) { pool[i] = node->val; node = node->next; i++; } while(node != nullptr) { int d = rand() % (i+1); // 随机获得一个[0,i]内的整数 if(d < m) { // 如果整数落在[0,m-1]范围内,则替换蓄水池中的元素 pool[d] = node->val; } node = node->next; i++; } return pool; } |
蓄水池抽样示例: