【算法】洗牌问题 - leetcode 384 打乱数组

方式:

1.暴力法

将所有的数放入一个容器内,随机取数值,以此形成一个数组。

就和概率论中不放回抽奖一样 我们是可以得到选中每一个球的概率是:
1 n \frac{1}{n} n1
对于实现这个算法来说我们需要将所有的数组取一个随机数并%上数组的当前最大值,然后移除该数据。

获取当前的值随机元素方式:

 public int[] shuffle() {
        List<Integer> aux = getArrayCopy();

        for (int i = 0; i < array.length; i++) {
            int removeIdx = rand.nextInt(aux.size());
            array[i] = aux.get(removeIdx);
            aux.remove(removeIdx);
        }
        return array;
    }

如此这般可以将一次取出元素组成一个随机的数组。

分析:

该算法的由于每一次都要remove 移动一遍,所以成本是
σ ( [ n 2 ] ) \sigma \left ( \left [ n^{2} \right ] \right ) σ([n2])
空间上需要有另一个数据来存储数据所以空间复杂度是n。


2.Fisher-Yates

既然这样我们是否可以通过某些优化从而避免较少的删除上的移动呢?

我们可以选择交换相关的元素从而使得数组变得更加随机,即从第一个元素开始,从后面的数中随机挑选一个数进行交换。以此类推。

代码如下:

 public int[] shuffle() {
     for (int i = 0; i < array.length; i++) {
         swapAt(i, randRange(i, array.length));
     }
     return array;
 }

因为是从头到尾扫描一遍 因此该算法的时间负责度为n。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值