洗牌算法

1.   背景

阿里的面试的时候做的一道笔试题:题目:写一个方法,入参为自然数n  (n > 0),返回一个自然数数组,数组长度为n,元素为[1,n]之间,且每个元素不重复,数组中各元素顺序要求随机;

实例1: 输入: N = 3  输出: 132

实例2: 输入: N = 5   输出: 32514

当时我的解法(写了两种方法):

写的好烂,面完和面试官交流的时候面试官让我看下Collections.shuffle的源码,于是乎就开始研究这个“洗牌算法”。

2.洗牌算法

洗牌就是将原有的排序打乱的一个过程,我们可以通过抽牌、换牌和插牌三种方式进行洗牌。最常用的洗牌算法:即Fisher-Yates Shuffle和Knuth-Durstenfeld Shhuffle,我们分别学习一下两种洗牌算法。

2.1 Fisher-Yates Shuffle

所述费舍尔-耶茨洗牌是一种算法:用于产生随机排列的有限的序列,简单地说,该算法对序列进行洗牌。

算法的自然语言描述为(给定1到N的序列):①记下从1到N的数字。

②从1到结尾的未删除数字(包括)之间选择一个随机数k。

③从低端开始计数,剔除尚未剔除的第k个数字,并将其写下一个单独的列表的末尾。

④从第2步开始重复,直到所有数字都被删除。

⑤现在在步骤3中写下的数字序列就是原始序列的随机排列。

理论上的费舍尔-耶茨洗牌算法的时间复杂度为O(n²),空间复杂度O(n)。

2.2 Knuth-Durstenfeld Shuffle

所述克努斯-杜斯腾菲尔德算法是一个现代版的费舍尔-耶茨算法,我们实现Fisher和Yates算法时会花费不必要的时间来用来计算上面第3步中的剩余数字,但Durstenfeld的解决方案是将“删除”的数字移到列表的末尾,然后将每个被删除的数字交换为最后一个未删除的数字迭代,简言之:每次迭代时交换这个被取出的数字到原始列表的最后。这将算法的时间复杂度从O(n²)降低到了O(n)。

伪代码实现://To shuffle an arrayaofnelements  (indices  0...n-1):

forifromn−1down to1do

j← random integer such that 0 ≤j≤iexchangea[j] anda[i]

按照上述的伪代码的描述,我们使用JS实现这段伪代码:

使用ES6实现的

Knuth-Durstenfeld Shuffle

算法需要的时间正比于要随机置乱的数,不需要额为的存储空间开销,时间复杂度为O(n),空间复杂度O(1)。

3.

Collections.shuffle()

源码解析:

shuffle方法的入口

传入待洗牌的List集合,定义一个随机数种子。

shuffle的具体实现

获取集合的长度,其中SHUFFLE_THRESHOLD = 5,当list的长度<5或者list实现了RandomAccess接口的时候,通过倒序的循环交换索引位置与随机生成的[0,i)的索引位置。

当集合长度>5的时候,将集合转为数组,然后再次进行随机值交换,然后将数组重新set到集合里面去,这样做避免了将“顺序访问”列表洗牌到适当的位置而导致的二次行为。

主意事项:

1)用List list=ArrayList(Arrays.asList(ia)),用shuffle()打乱不会改变底层数组的顺序。

2)用List list=Arrays.aslist(ia),然后用shuffle()打乱会改变底层数组的顺序。

可以使用洗牌算法实现扫雷。

shuffle洗牌算法java_洗牌算法shuffle相关推荐

  1. 最长公共子序列算法 java_转【算法之动态规划(三)】动态规划算法之:最长公共子序列 最长公共子串(LCS)字符串相似度算法...

    1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题 ...

  2. 21朵水仙花算法java_水仙花数算法 - hi_jyf - OSCHINA - 中文开源技术交流社区

    小博在面试中碰到的这个问题,虽然写的比较简单,还是觉得有必要整理一下.当然,如果您有更好的写法,还望不吝赐教. package com.web.demo.algorithm; import java. ...

  3. 模拟退火算法 java_转 | 模拟退火算法(SA)和迭代局部搜索(ILS)求解TSP的Java代码分享...

    以下文章来源于数据魔术师 ,作者周航 前言 大家好呀!我们你们好久不见的...咳咳,初次见面的小编! 之前重新整理了ILS的代码,有人留言问能不能提供java版. 正好最近在学启发式算法和java,为 ...

  4. kruskal算法java_克鲁斯卡尔算法(Kruskal)的java实现

    下面是我对软件工程教程里面的克鲁斯卡尔算法的实现,发现在网是很少有网友贴出,为了方便大家查询,所以贴出来了,还希望大家能多指点. package Test; import java.io.Buffer ...

  5. python实现洗牌算法_洗牌算法及 random 中 shuffle 方法和 sample 方法浅析

    对于算法书买了一本又一本却没一本读完超过 10%,Leetcode 刷题从来没坚持超过 3 天的我来说,算法能力真的是渣渣.但是,今天决定写一篇跟算法有关的文章.起因是读了吴师兄的文章 <扫雷与 ...

  6. 随机洗牌算法+matlab,洗牌算法及 random 中 shuffle 方法和 sample 方法浅析

    对于算法书买了一本又一本却没一本读完超过 10%,Leetcode 刷题从来没坚持超过 3 天的我来说,算法能力真的是渣渣.但是,今天决定写一篇跟算法有关的文章.起因是读了吴师兄的文章<扫雷与算 ...

  7. Java实现 蓝桥杯VIP 算法提高 洗牌

    算法提高 洗牌 时间限制:1.0s 内存限制:256.0MB 问题描述 小弱T在闲暇的时候会和室友打扑克,输的人就要负责洗牌.虽然小弱T不怎么会洗牌,但是他却总是输. 渐渐地小弱T发现了一个规律:只要 ...

  8. 通过程序实现斗地主过程中的洗牌,发牌和看牌(简约版)

    需求:通过程序实现斗地主过程中的洗牌,发牌和看牌 思路: 创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现 往牌盒里面装牌 洗牌,也就是说把牌打撒,用Collections的shuf ...

  9. C语言麻将递归,C++数据结构与算法——麻将胡牌算法(二:完全胡牌算法)

    虽然单花色胡牌算法面试时写出来了,但是完整的胡牌算法却没有写,既然遇到了,秉着不抛弃不放弃的精神,当然不能原谅懒惰的自己了.下面这篇为一个完整的胡牌算法. 胡牌规则除了以下几点,其余与单花色胡牌规则一 ...

最新文章

  1. C#编程(十六)----------匿名类型
  2. 手机端网站排名优化需注意哪些细节?
  3. 回复:lerit的关于对象中字段的初始化问题
  4. HTML5 中的canvas元素用于,HTML5中的Canvas元素
  5. visio 程序设计流程图合符号含义
  6. Window10:不能建立到远程计算机的连接。你可能需要更改此连接的网络设置。
  7. shell 进入hadoop_Hadoop关于HDFS的基本操作(Shell命令)
  8. 自监督学习的一些思考
  9. 刷题笔记(1) 一个序列是否为二叉搜索树的遍历结果
  10. 1.3、解析并创建ApplicationListener(ok)
  11. 线程池如何保证所有子线程运行完再执行主线程
  12. linux查看app路径下文件卡死
  13. 原生安卓10怎么打开面部识别_安卓手机运行慢怎么办?只需简单一步立即提速翻倍...
  14. 电商项目---完成内容管理cms系统
  15. 2021-03-12 16个车辆信息检测数据集收集汇总
  16. WEB2.0是什么东东?[转]
  17. 效果图渲染器详解,出图最快的竟然是它!
  18. 百度人脸识别 人脸识别模型_人脸识别的现代君主制
  19. 300 秒就完成第一超算 1 万年的计算量,量子霸权真时代要来了吗
  20. 蔡颖-《APS走向实践》书解读之一:APS优化供应链从绩效指标开始

热门文章

  1. CentOS8安装QT5.12的问题
  2. python-纯函数
  3. android 记事本ppt,基于Android记事本软件设计与实现.ppt
  4. Element Table 反选
  5. 腾讯优图:开源 YOLO 系列代码(含 YOLOv3 以及各种 Backbone)
  6. MIMO中SM系统原理与仿真
  7. 玩转ChatGPT:Auto-GPT项目部署与测评
  8. 手握2亿美金,专挑“硬骨头”?The Engine公布第一批“改变世界”的被投公司名单...
  9. ServerRoot must be a valid directory
  10. 应用是非正式发布版本, 当前设备不支持安装。