前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[洗牌算法] - 从长度为m的int数组中随机取出n个元素,每次取的元素都是之前未取过的

[洗牌算法] - 从长度为m的int数组中随机取出n个元素,每次取的元素都是之前未取过的

作者头像
103style
发布2022-12-19 13:53:52
1.6K0
发布2022-12-19 13:53:52
举报

题目:从长度为m的int数组中随机取出n个元素,每次取的元素都是之前未取过的

Fisher-Yates洗牌算法是由 Ronald A.Fisher和Frank Yates于1938年发明的,后来被Knuth在书中介绍,很多人直接称Knuth洗牌算法, Knuth大家应该比较熟悉,《The Art of Computer Programming》作者,算法理论的创始人。我们现在所使用的各种算法复杂度分析的符号,就是他发明的。

等概率: 洗牌算法有些人也称等概率洗牌算法,其实发牌的过程和我们抽签一样的,大学概率论讲过抽签是等概率的,同样洗牌算法选中每个元素是等概率的。

用洗牌算法思路从1、2、3、4、5这5个数中,随机取一个数

1
1

4被抽中的概率是1/5

5被抽中的概率是1/4 * 4/5 = 1/5

2被抽中的概率是1/3 * 3/4 * 4/5 = 1/5

1被抽中的概率是1/2 * 1/3 * 3/4 * 4/5= 1/5

3被抽中的概率是1 * 1/2 * 1/3 * 3/4 * 4/5 = 1/5

时间复杂度为O(n^2), 空间复杂度为O(n)

代码如下:

代码语言:javascript
复制
//O(N^2)time
//O(N)space
void test(int n, int m) {
    List<Integer> list = new ArrayList<>();
    for (int i = 1; i <= n; i++) {
        list.add(i);
    }
    for (int i = 0; i < m; i++) {
        int t = (int) (list.size() * Math.random());
        System.out.println(list.remove(t));
    }
}

Knuth洗牌算法

在上面的介绍的发牌过程中, Knuth 和 Durstenfeld 在Fisher 等人的基础上对算法进行了改进,在原始数组上对数字进行交互,省去了额外O(n)的空间。该算法的基本思想和 Fisher 类似,每次从未处理的数据中随机取出一个数字,然后把该数字放在数组的尾部,即数组尾部存放的是已经处理过的数字。

时间复杂度为O(n), 空间复杂度为O(n)

代码语言:javascript
复制
//O(N)time
//O(N)space
void knuth(int n, int m) {
    int[] arr = new int[n];
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }
    for (int i = 0; i < m; i++) {
        int index = (int) ((n - i) * Math.random());
        System.out.println(arr[i + index]);
        swap(arr, i, i + index);
    }
}

void swap(int[] arr, int i, int index) {
    if (i == index) return;
    int temp = arr[i];
    arr[i] = arr[index];
    arr[index] = temp;
}

参考链接

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题目:从长度为m的int数组中随机取出n个元素,每次取的元素都是之前未取过的
  • Knuth洗牌算法
  • 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档