您的位置:首页 > 其它

随机地生成n个不超过n且不重复的正整数

2015-05-10 15:36 447 查看

许久以前,参加校园招聘,在面试时被问到“如何随机地生成n个不超过n且不重复的正整数”。你会怎么做呢?n的值具体是多少并不重要,我们关心的重点是如何在n确定时设计一种法案来解决随机产生不重复的数的问题。下面就以n =100为例来说明几种实现方式,将产生的随机数存放于数组中。

方案1.
话说当时见识少,功夫不到家,认为每次随机生成数字,再判断该数字是否已经重复,如果不重复则保留该值,否则重新产生新的随机数字。

import java.util.Random;

public classGenerateRandom {
static final int Number= 100;

public static voidmain(String[] args) {
int[] Data = new int[Number];
GenRandom1(Data);
}

private static voidGenRandom1(int[] In_Array) {
for(int i = 0; i < Number; i++) {
In_Array[i] = -1;  //初始化
}

Random random = newRandom();
int count = 0;  //count用来控制生成n个数
while(count < Number) {
int index = random.nextInt(Number-1);//随机生成小于n的数
int i = 0;
for(i = 0; i < Number; i++) {//查重
if(In_Array[i] == index)
break;
}
if(i == Number) { //i小于n时表明已重复,否则不重复
In_Array[count] = index;
count++;
}
index = random.nextInt(Number);
}
}
}

该方法能实现我们所需要完成的功能,但是稍微想想,这种方式效率非常低,每次生成随机数后都需要判断是否和已产生的随机数重复,需要耗费n的时间复杂度,并且越往后重复的概率越大,当前面生成了n-1个数,需要产生第n个数时,可能需要产生几十个数,每次产生都需要查重,导致生成一个数可能耗费成千上万次运算。

方案2.
再来思考一下题目:随机产生n个不超过n的不重复的数字,不就是将0到n-1的n个数的顺序打乱么。
首先初始化数组,按序填充数组,接下来就是随机改变数组中元素的位置。如何改变数组中元素的位置,最简单的方式就是随机产生两个数,交换以这两个数为下标的元素。
private static voidGeneRandom2(int[] In_Array) {
for(inti = 0; i < Number; i++) {
In_Array[i] = i;
}

Random random = newRandom();
for(int i = 0; i < Number; i++) {
intr1 = random.nextInt(Number- 1);
intr2 = random.nextInt(Number- 1);
if(r1 != r2) {
inttemp = In_Array[r1];
In_Array[r1] = In_Array[r2];
In_Array[r2] = temp;
}
}
}

该方案相对方案一简洁了许多,时间复杂度降低了许多。但是在仔细想一想,是最好的么,能否再进行优化?

方案3.
将code从前往后仔细读了几次,存在着两个小疑惑:1.能不能每次只产生一个随机数?2.很有可能有些位置上的元素被交换了好几次,但有些位置上的元素一次也不进行交换,能否确保每个位置上的元素都被交换?
for(inti = 0; i < Number; i++) {
intr1 = random.nextInt(Number- 1);
if(r1 != i) {
inttemp = In_Array[r1];
In_Array[r1] = In_Array[i];
In_Array[i] = temp;
}
}

思考到这里,这似乎是最简洁的方式了。隐隐觉得还有所欠缺,但没能想到解决方案。最近看到编程珠玑上有一种新的解法,盛是精辟。
Random random = newRandom();
for(int i = Number- 1; i > 0; i--) {
int index = random.nextInt(i);
inttemp = In_Array[index];
In_Array[index] = In_Array[i];
In_Array[i] = temp;
}

每次产生不大于i的数,将以该数字为下标的元素和以i为下标的元素进行交换,确保位子全部被调换,又比上面的发法巧妙多了(没有随机排序的概率小多了)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: