概率算法 -- 从集合中选取N个不重复的元素

概率重复的从n个数中选取m个数 问题描述:程序的输入包含两个整数m和n,其中m 学习过概率统计的同学应该都知道每一个数字被抽取的概率都应该为m/n. 那么我们怎么构造出这样的概率呢?在《编程珠玑》上面是这样解析的:   依次考虑整数0,1,2,.....,n-1,并通过一个适当的随机测试对每个整数进行择。通过按序访问整数,我们可以保证输出结果是有序的。 假如我们考虑m = 2,n = 5的情况,那么择的每一个数字的概率 阅读详情

      这个问题见了很多,一般表述是,1到n的整数中随机选k个这k个不能重复。变一下即可以是n个元素选k个,不能重复。

 

    有不同复杂度的算法。第一个是笨办法:

(1)随机选一个数,然后判断这个数字是否已经被选过了(是否重复),不过不重复,那就就选他了,如果重复,就再随机选一个。

空间复杂度:O(1)

时间复杂度:O(k^2)

而且有一个问题,如果是100个选90个,那么最后冲突的概率很大,选一个数字要重复随机好多次才行。效率低。不要。

如果用hash来解决判重的问题:

空间:O(n)

时间:O(k)

 

(2)第二种是第一种的改进。先在1到n-k+1中随机选一个,然后把范围扩大到n-k+2,再随机选一个,如果随机选中的是之前已经选过的,那么就选择第n-k+2个元素。

比如:从1-8中选4个数字。

第一步.从1到5中随机选一个,比如选了2.

第二步。从1到6中随机选一个。如果选出的是i=1,3,4,5,6,那么就选i即可。如果选出的是2,这个时候就重复了,此时的处理方式是选择i=6。

第三步,从1到7中随机选一个数,如果跟之前的重复,那么就选那种7.

第四步从1到8中随机选一个数,如个之前的重复,就选8。

 

空间复杂度:O(1)

时间复杂度:O(k^2)

这种方法确保每次都能产生随机数。避免了第一种方法的问题。

方法1和方法2都可以用hash来解决判重时的消耗。

此时方法2的复杂度为:

空间:O(n)

时间:O(k)

 

(3)方法3是经典的交换法。

产生第一个随机元数,将其交换到数组的第一个位置a[0]。这样,只要在a[1]和a[n-1]中随机选泽,即可以确保不重复了。

所以,再在a[1]到a[n-1]中产生一个随机数,交换到a[1]位置,。。。。

空间:O(n)

时间:O(k)

 

(4)因为是从n个中产生k个,所以每个元素选中的概率是k/n。

所以,对于a[0],以k/n的概率选泽他。如果选中了,那么对剩下的数组来说,就是在n-1个元素中选k-1个元素的问题;如果没选中,那么

对剩下的数组来说,就是在n-1个元素中选k个元素的问题。迭代即可。

时间复杂度:O(n)

空间复杂度:O(1)

这个算法不一定要遍历到最后才结束,如果已经选够了n个数,就可以结束了。

 

(5)先选中前k个元素,然后开始遍历剩下的元素,如第k+1个元素来的时候,以k/(1+k)的概率去替换之前k个元素中的一个。至于替换哪一个,就是均匀的选了。

对于新来的这个元素,被选中的概率是:k/(k+1) (替换)

对于之前的元素,被选中的概率是:(1-k/(k+1))+k/(k+1) * (k-1)/k   = 1/(k+1) + (k-1)/(k+1)= k/(+1)   (不替换+替换但没被选中替换出去)

第k+2个元素来的时候,以k/(k+2)的概率去替换之前k个元素中的一个。

 

时间复杂度:O(n)

空间复杂度:O(1)

这种方法还适合在总数量未知的情况下使用。

 

O(n)的算法未必比O(k^2)的算法好,注意n和k的区别。比如在全体4字节长的整数中随机选3个不重复的,就不要用(4)和(5)了。

 

概率/随机数算法 包含主要的概率/随机数问题相关算法 阅读详情

相关推荐

0049算法笔记——【随机化算法】蒙特卡罗算法,主元素问题,素数测试问题

1、蒙特卡罗算法       基本概述        蒙特卡罗(Monte Carlo)方,又称随机抽样或统计试验方。传统的经验方由于不能逼近真实的物理过程,很难得到满意的结果,而蒙特卡罗方由于能够真实地模拟实际物理过程,故解决问题与实际非常符合,可以得到很圆满的结果。       在实际应用中常会遇到一些问题,论采用确定性算法或随机化算法都无保证每次都能得到正确的解答。蒙特卡罗

liufeng_king的专栏 1万+

n个数组各取一数的重复组合

package collection; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class Postion {

zyn010101的专栏 1409

组合问题(含有重复元素

文章目录一、初识组合二、组合代码描述1.简单的组合数量问题2.枚举出每一种的组合情况3.使用next_permutation枚举出所有组合结果 一、初识组合 可以参考:https://www.cnblogs.com/fengxunling/p/9687162.html 二、组合代码描述 1.简单的组合数量问题 描述:从n个里面择m个进行相关组合排序,考虑m个元素的位置。 代码如下(示例): #include <bits/stdc++.h> using namespace std; int

drawlessonsfrom的博客 499

组合1.无重复元素

利用begin 结束条件为满足条件 就这 class Solution { List<List<Integer>> res =new ArrayList<List<Integer>>(); public List<List<Integer>> combinationSum(int[] candidates, int target) { if(candidates.length==0){

weixin_47040809的博客 183

求从几个集合中各选取一个元素,并组合的算法

初学python,因为需要,就用 python 简单实现了下,各种语言都一样,需要递归。 # A Recursion function 递归函数 def RecursionFunc(arr1,arrList): if (arrList): string = [] for x in arr1: for y in arrList[0]

一路向前 3237

两个集合得到之间重复的数据

String[] arr1 = {"1", "2", "3", "4", "5"}; String[] arr2 = {"1", "2", "4", "5"}; List&lt;String&gt; list = new ArrayList&lt;&gt;(); for(int i = 0, ma

aa503709643的博客 1897

概率选取问题 Random Pick

概率选取问题要求保证选取的随机性,即

LUCKYOJ 3786

Java 随机数之从指定数据范围内随机选取n个重复的数据

Java 随机数之从指定数据范围内随机选取n个重复的数据 一、简述 记--从指定数据范围内随机选取n个重复的数据,如从1~100中随机选取10个数据。 二、效果 三、工程结构 四、源文件 import java.util.ArrayList; import java.util.List; import java.u...

Genven_Liang的博客 4359

随机算法 实现估算集合的势

问题描述:估算一个集合元素个数

感悟编程 1243

求解0-n中(包含0,但包含n)m个重复随机数算法.

//求解0-n中(包含0,但包含n)m个重复随机数算法. C/C++ code void knuth(int n, int m) { srand( (unsigned)time( NULL ) ); for( int i = 0; i n; i++) { if( rand()%(n-i) m) {

maoloverme1的专栏 1657

概率算法笔记

概率算法

qq_40438523的博客 1141

java 随机 集合 子集_随机集合的子元素集合

我需要一个从集合N中随机择M个子元素算法。 当然最好的办是将集合打乱顺序,然后从中选择前M个元素即可。 Java中现成的API可以使用:java.util.Collections.shuffle(List>)此算法非常简单,循环N次,每次长度减少1,随机获取其中一个元素,然后交换其对称元素。public static void shuffle(List> list, Random...

weixin_32009069的博客 510

20概率算法

概率算法   随机性(randomness)是偶然性的一种形式,是某一事件集合中的各个事件所表现出来的确定性。产生某一随机性事件集合的过程,是一个定因子断产生的重复过程,但它可能遵循某个概率分布。   随机序列(random sequence),更确切的,应该叫做随机变量序列,也就是随机变量形成的序列。一般的,如果用X1,X2……Xn代表随机变量,这些随机变量如果按照一定顺序出现,就形成...

weixin_30267691的博客 577
上一篇: 概率算法-均匀分布产生正态分布
下一篇: 概率算法 -- 洗牌
纯属虚构
博客等级 码龄16年 86粉丝 194原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值