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.

  • 相关阅读:
    oracle中rownum和rowid的区别和用法
    jsp中,对window对象的简单总结
    下拉列表框实现二级联动
    window.showModalDialog()的简单用法
    javascript中的正则表达式
    java实现树型结构样式
    几个数据库的驱动、连接
    Java桌面程序中设置一个软件的系统托盘
    【动态规划】求两字符串连续最大公共子串长度
    大整数相乘
  • 原文地址:https://www.cnblogs.com/tonyluis/p/5944338.html
Copyright © 2011-2022 走看看