zoukankan      html  css  js  c++  java
  • 洗牌算法

    洗牌算法一:
    生成一个不重复的随机序列,将随机序列绑定到nums[],然后对随机序列做一次排序。


    洗牌算法二:(经典洗牌算法)

    for(int i=nums.length-1; i>=1; i--) 
      Swap(nums[i], nums[rand()%(i+1)]); 

    经典算法的证明:

    对于nums[i],洗牌后在第n-1个位置的概率是1/n(第一次交换的随机数为i)
    在n-2个位置概率是[(n-1)/n] * [1/(n-1)] = 1/n,(第一次交换的随机数不为i,第二次为nums[i]所在的位置(注意,若i=n-1,第一交换nums[n-1]会被换到一个随机的位置))
    在第n-k个位置的概率是[(n-1)/n] * [(n-2)/(n-1)] *...* [(n-k+1)/(n-k+2)] *[1/(n-k+1)] = 1/n
    (第一个随机数不要为i,第二次不为nums[i]所在的位置(随着交换有可能会变)……第n-k次为nums[i]所在的位置)

    洗牌算法三:(inside-out算法,可用于未知牌数)

    类似于蓄水池抽样算法。

    int i=0;
    while(nums[i]存在)
    {
    	int k = rand()%(i + 1);
    	res[i] = res[k];
    	res[k] = nums[i++];
    }

    上面是伪代码,如果知道nums的lenght的话,可以改为for循环,由于是从前往后遍历,所以可以应对nums[]数目未知的情况,或者nums[]是一个动态增加的情况。

    证明如下:

    原数组的第 i 个元素在新数组的前 i 个位置的概率都是:(1/i) * [i/(i+1)] * [(i+1)/(i+2)] *...* [(n-1)/n] = 1/n,(即第i次刚好随机放到了该位置,在后面的n-i 次选择中该数字不被选中)

    原数组的第 i 个元素在新数组的 i+1 (包括i + 1)以后的位置(假设是第k个位置)的概率是:(1/k) * [k/(k+1)] * [(k+1)/(k+2)] *...* [(n-1)/n] = 1/n(即第k次刚好随机放到了该位置,在后面的n-k次选择中该数字不被选中)

    蓄水池抽样:

    问题:如何随机从n个对象中选择一个对象,这n个对象是按序排列的,但是在此之前你是不知道n的值的。

    解法:我们总是选择第一个对象,以1/2的概率选择第二个,以1/3的概率选择第三个,以此类推,以1/m的概率选择第m个对象。当该过程结束时,每一个对象具有相同的选中概率,即1/n.

  • 相关阅读:
    Linux下MySQL/MariaDB Galera集群搭建过程
    Linux下Nginx+Tomcat负载均衡和动静分离配置要点
    快速部署tomcat项目的Shell脚本
    利用缓存实现APP端与服务器接口交互的Session控制
    基于xml的Spring多数据源配置和使用
    基于注解的Spring多数据源配置和使用
    MySQL 开启事件 使用定时器调用存储过程
    MyBatis绑定错误--BindingException:Invalid bound statement (not found)
    micropython1.16官方文档转PDF
    dokuwiki使用随笔
  • 原文地址:https://www.cnblogs.com/tonyluis/p/5944338.html
Copyright © 2011-2022 走看看