shuffle洗牌算法java_洗牌算法shuffle[通俗易懂]

洗牌算法1.背景阿里的面试的时候做的一道笔试题:题目:写一个方法,入参为自然数n(n>0),返回一个自然数数组,数组长度为n,元素为[1,n]之间,且每个元素不重复,数组中各元素顺序要求随机;实例1:输入:N=3输出:132实例2:输入:N=5输出:32514当时我的解法(写了两种方法):写的好烂,面完和面试官交流的时候面试官让我看下Collect…

大家好,又见面了,我是你们的朋友全栈君。

5f86bc314e29

洗牌算法

1.   背景

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

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

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

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

5f86bc314e29

5f86bc314e29

写的好烂,面完和面试官交流的时候面试官让我看下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实现这段伪代码:

5f86bc314e29

使用ES6实现的

Knuth-Durstenfeld Shuffle

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

3.

Collections.shuffle()

源码解析:

5f86bc314e29

shuffle方法的入口

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

5f86bc314e29

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()打乱会改变底层数组的顺序。

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/126128.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • UDP协议抓包分析

    UDP协议抓包分析一、什么是UDPUDP就是一种无连接的协议。该协议用来支撑那些需要在计算机之间传输数据的网络应用,包括网络视频会议系统在内的众多客户/服务器模式的应用。二、UDP协议的特点UDP使用底层的互联网协议来传送报文,同IP一样提供不可靠的无连接传输服务。他也不提供报文到达确认、排序及流量控制等功能。(1)UDP是一个无连接协议,也就是传输数据之前源端口和目标端口不能建立连接。当它想传输时,就简单…

    2022年5月11日
    180
  • vue中watch的用法

    vue中watch的用法当 vue 项目中需要对某个值进行监听做一些操作的时候我们会用到 watch 进行监听 1 监听普通属性 单一字符串 布尔值 等等 data return dvid goodsInfo userInfo closeTime 0 关仓倒计时 watch closeTime newVal oldVal console log newVal oldVal

    2025年6月21日
    5
  • 微信第三方登录接口购买_微信授权登录第三方网页

    微信第三方登录接口购买_微信授权登录第三方网页随着手机微信的崛起,腾讯发布的微信联登确实很诱惑pc端的伙伴们,现在就说说在pc端用微信扫一扫实现微信第三方登陆的方式。  第一步:获取AppID AppSecret(不做解释,自己去微信公众平台申请)第二步:生成扫描二维码,获取codehttps://open.weixin.qq.com/connect/qrconnect?appid=AppID&amp;redirect_uri=http://…

    2025年6月19日
    4
  • 单模和多模光纤可以混用吗_多模光纤和单模光纤能混用吗

    单模和多模光纤可以混用吗_多模光纤和单模光纤能混用吗我们知道光纤和光模块都有单模和多模两种类型,那么我们可能在使用中会产生疑问,单模/多模光纤和单模/多模光模块如何配套使用?它们可以混用吗?下面飞速光纤将通过问答的方式来为大家解答这个疑惑。  问:单模光纤和多模光纤有什么区别?  答:单模光纤采用固体激光器做光源;多模光纤则采用发光二极管做光源;单模光纤传输频带宽、传输距离长,但因其需要激光源,成本较高;多模光纤传输速度低、距离短,但其成本比较低;单模光纤芯径和色散小,仅允许一种模式传输;多模光纤芯径和色散大,允许上百种模式传输。  问:单模光模块和多模

    2022年9月25日
    4
  • html怎么让背景图片自适应屏幕大小_css背景图片拉伸填充

    html怎么让背景图片自适应屏幕大小_css背景图片拉伸填充html如何让背景图片充满全图,就是拉伸html语言背景图片拉伸代码:background-size:cover,可以使图片拉伸铺满背景。拓展资料背景(background)属性定义元素的背景效果元素的背景区包括前景之下直到边框边界的所有空间。因此,内容框与内边距都是元素背景的一部分。取值:repeat、no-repeat、repeat-x、repeat-y。repeat:默…

    2022年10月5日
    2
  • java线程池面试题_java之线程池面试题

    java线程池面试题_java之线程池面试题面试官:线程池有哪些?分别的作用是什么?常用的线程池有:newSingleThreadExecutornewFixedThreadExecutornewCacheThreadExecutornewScheduleThreadExecutor1、newSingleThreadExecutor:单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务;2、newFixedThreadExe…

    2022年5月22日
    26

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号