n个热门物品中,随机选择k个物品

Posted xiaoranone

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了n个热门物品中,随机选择k个物品相关的知识,希望对你有一定的参考价值。

背景:
在推荐系统中,都会维护一个热门的物品的list,可能会有很多人在这个list进行添加。有时我们需要从这个list中随机选择k个热门物品返回给用户,现在如何设计一个函数解决这个问题。

我们要注意两个问题,

  1. list是增加的,对于增加的数据结构,可以选择一个链表作为基础结构,而不能选择数组。
  2. 要保证每个物品别选择的概率是相同的,即每一个物品选择的概率都是k / n.(n是长度)

首先定义链表的数据结构
struct listNode
int index; // the index of item
struct listNode * next;
;

目前先给出一个简单的C++代码,马上添加证明,是否满足每一个别选择的概率相同。

/**
 * Author: xiaoran
 * Time: 2018-09-19 16:50
 * 
 */ 

#include <bits\\stdc++.h>
using namespace std;

struct listNode 
    int index;// the index of item
    struct ListNode * next;
;

int getlength(listNode * head) 
    if(head == NULL) return 0;
    int length = 0;
    listNode * p = head;
    while(p) 
        length ++;
        p = p->next;
    
    return length;


listNode * getKnode(listNode * head, int k) 
    listNode * p = head;
    int cnt = 0;
    while(p && cnt < k) 
        p = p->next;
        cnt ++;
    
    return p;



/**
 * 1. 因为list是长度的增加的,首先计算list长度
 * 2. 每次选择产生一个下标,选择这个下标的对应的值
 * 3. 如果当前随机产生的值,不在选则的集合中,则进行插入
 * 4. 直到集合大小是k个
 */ 
void selectKitemsOne(listNode * head, int k, vector<int> &candidate) 
    if(! head) return;
    int n = getlength(head);
    if(k > n) return;

    // 使用set,记录每次选择的下标
    set<int> tmp;
    while(tmp.size() < k) 
        int i = rand() % n;
        if(tmp.find(i) == tmp.end())  // 不在集合中进行插入
            tmp.insert(i); // 这里不能直接插入第i个元素的index,因为我们用的list,不能直接取到第i个值
        
    
    // 得到candidate
    for(auto it = tmp.begin(); it != tmp.end(); it ++) 
        candidate.push_back(getKnode(*it));
    



/**
 * 1. 初始化前k个作为候选集
 * 2. 从i = k-->n进行遍历,
 * 3. 随机产生j = rand() % (i+1), if (j < k) candidate[j] = 第i个的index
 */  
void selectKitemsTwo(listNode * head, int k, vector<int> &candidate) 
    if(! head) return;
    int i = 0;
    listNode * p = head;
    while(p && i < k) 
        candidate.push_back(p->index);
        i ++;
    

    while(p) 
        int j = rand() % (i+1);
        if(j < k) 
            candidate[j] = p->index;
        
        p = p->next;
        i ++;
    


int main()

    return 0;

证明:稍后

以上是关于n个热门物品中,随机选择k个物品的主要内容,如果未能解决你的问题,请参考以下文章

Problem 6 二分

解题报告

hihocoder-1486物品价值(状压dp)

Luogu4640 BJWC2008 王之财宝 容斥卢卡斯定理

洛谷 P2822 组合数问题 如题

P2822 组合数问题