IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 蓄水池算法 链表的随机节点 随机数索引 C++ -> 正文阅读

[数据结构与算法]蓄水池算法 链表的随机节点 随机数索引 C++

蓄水池算法

问题描述:

1.从10000个编号为1-10000的人中随机抽100个调查

2.从80亿个编号为1-80亿的人中随机抽取100个调查

对于第一个问题,可以把10000个人的信息读取到数组中,调用库函数rand(),随机访问。第二个问题也可以读取到数组中,显然,这种方法不可取。


问题描述:要求从N个元素中随机的抽取k个元素,其中N无法确定。

问题定义可以简化如下:在不知道文件总行数的情况下,如何从文件中随机的抽取一行?

给出解决方案:在扫描第i个行时,以1/i的概率选择该行,选择意味着选取当前行并替换前面已经选到的那行。即,扫描到第一行时,选择;扫描到第二个行时,以1/2的概率替换第一个行;扫描到第三个行时,以1/3的概率替换前面选取的行,以此类推,直至扫描完一遍后,选取到的行号恰好是等概率的。

证明:设行号为[1…N],即证明选取每行的概率为1/N。设1<= i <=N,选取到第i行的事件为第i次选取了第i行且后面每次选择过程中均没有选中。概率为:抽到第i行的概率( 1 i \frac{1}{i} i1?) ** 抽到第i行但是没有替换第i行的概率(1 - 1 n \frac{1}{n} n1?) **。比如说抽到第三行时,第三行出现的概率为( 1 3 \frac{1}{3} 31?),但是没有选中第三行的概率是(1 - 1 3 \frac{1}{3} 31?)

p = 1 i \frac{1}{i} i1???????X (1 - 1 i + 1 \frac{1}{i + 1} i+11???????)X (1 - 1 i + 2 \frac{1}{i + 2} i+21???????)X (1 - 1 i + 3 \frac{1}{i + 3} i+31???????)X (1 - 1 i + 4 \frac{1}{i + 4} i+41???????)X …X (1 - 1 n \frac{1}{n} n1????????)

= 1 i \frac{1}{i} i1?????????X ( i i + 1 \frac{i}{i + 1} i+1i?????????)X ( 1 + i i + 2 \frac{1 + i}{i + 2} i+21+i?????????)X ( i + 2 i + 3 \frac{i + 2}{i + 3} i+3i+2?????????)X ( i + 3 i + 4 \frac{i + 3}{i + 4} i+4i+3?????????)X …X ( n ? 1 n \frac{n - 1}{n} nn?1???????????)

= 1 n \frac{1}{n} n1?

在不知道行数的情况下,如果遍历到最后一行,保留的仍然是第一行的情况

第一行,抽到第一行的概率为:1

第二行,抽到第二行的概率为: 1 2 \frac{1}{2} 21??,抽到第二行但是没有替换第一行的概率,1 x ( 1 - 1 2 \frac{1}{2} 21??) = 1 2 \frac{1}{2} 21??,如果行数为2,那么1,2出现的概率都为 1 2 \frac{1}{2} 21??

第三行,抽到第三行的概率为: 1 3 \frac{1}{3} 31?,抽到第二行但是没有替换第一行的概率,1 x (1 - 1 2 \frac{1}{2} 21?) x (1 - 1 3 \frac{1}{3} 31?) = 1 3 \frac{1}{3} 31?,如果行数为3,那么1,2,3出现的概率都为 1 3 \frac{1}{3} 31??

第四行,抽到第四行的概率为: 1 4 \frac{1}{4} 41?,抽到第二行但是没有替换第一行的概率,1 x (1 - 1 2 \frac{1}{2} 21?) x (1 - 1 3 \frac{1}{3} 31?) x (1 - 1 4 \frac{1}{4} 41?) = 1 4 \frac{1}{4} 41?,如果行数为4,那么1,2,3,4出现的概率都为 1 4 \frac{1}{4} 41??

第n行,抽到第n行的概率为: 1 n \frac{1}{n} n1???,抽到第n行但是没有替换第一行的概率,1 x (1 - 1 2 \frac{1}{2} 21???) x (1 - 1 3 \frac{1}{3} 31???) x (1 - 1 4 \frac{1}{4} 41???)x…x (1 - 1 n \frac{1}{n} n1???) = 1 n \frac{1}{n} n1??,如果行数为n,那么1,2,3,4,…,n出现的概率都为 1 n \frac{1}{n} n1???

推导完毕。第n行的原理也如此。


LeetCode 382.链表随机节点

题目描述:

给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。

进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?

代码实现

class Solution {
private:
    ListNode* head;
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() {
        ListNode* head = this->head;
        int k = 1;
        int val = head->val;
        while (head) {
            //在[0, k - 1]间,随机选一个数
            int num = rand() % k;
            //选中0的概率为:(1/k),如果为0代表选中第k - 1行,然后替换。p = 1 / k
            //未选中0的概率为(1 - 1/k),不替换,保留上次的结果。p = 1*(1-1/2)*(1-1/3)*...*(1-1/n)
            if (num == 0) {
                val = head->val;
            }
            k++;//k++,模拟行数的增加
            head = head->next;
        }
        return val;
    }
};


LeetCode 398.随机数索引

给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。

注意:
数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。

示例:

int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);

// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
solution.pick(3);

// pick(1) 应该返回 0。因为只有nums[0]等于1。
solution.pick(1);

class Solution {
    vector<int>nums;
public:
    Solution(vector<int>& nums) {
        this->nums = nums;
    }

    int pick(int target) {
        int n = nums.size();
        int k = 1;
        int index = 0;
        for (int i = 0; i < n; i++) {
            if (this->nums[i] == target) {
                if (rand() % k == 0) {
                    index = i;
                }
                k++;
            }
        }
        return index;
    }
};

提取k个时。

在这里插入图片描述
在这里插入图片描述

array S[n];    //source, 0-based
array R[k];    // result, 0-based
integer i, j;
 
// fill the reservoir array
for each i in 0 to k - 1 do
        R[i] = S[i]
done;
 
// replace elements with gradually decreasing probability
for each i in k to n do
        j = random(0, i);   // important: inclusive range
        if j < k then
                R[j] = S[i]
        fi
done
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章           查看所有文章
加:2021-07-31 16:53:22  更:2021-07-31 16:56:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/8 9:08:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码