在一次采访中,我被要求提供一种方法,每次调用它时都会生成唯一的5位数随机数。例如:如果我调用方法得到22222,那么在下次通话中我不应该得到22222。
我写了一个代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class RandomNumberGen {
private static ArrayList arr=new ArrayList();
private static int k=-1;
public RandomNumberGen(){
for (int i=10000;i<99999;i++){
arr.add(i);
}
Collections.shuffle(arr);
}
public static void main(String[] args) {
for(int m=0;m<10;m++){
try {
System.out.println(new RandomNumberGen().randomNumbermethod());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public Integer randomNumbermethod() throws Exception{
k++;
if(k>=arr.size()){
throw new Exception("No more number available");
}else return (Integer) arr.get(k);
}
}
答案被接受但我被要求现在避免记忆浪费。 我的问题在这里,因为你可以看到我只使用了10个数字。所以arraylist占用的剩余空间是一个记忆 - 浪费。有一种方法我可以实现同样的事情而不需要额外的记忆。 我的意思是在某种程度上使用哪个唯一编号可以在每个调用中生成,这样就不会浪费这么多内存。
答案 0 :(得分:6)
private static int number = 10000;
public int getNextUniqueRandomNumber() {
return number++;
}
答案 1 :(得分:6)
意义:
可以在集合(设置)中跟踪生成的数字。这意味着每个数字的开销为32位(当跟踪可用或生成的数字时)加上收集开销。另一种可能性是使用布尔数组并标记已使用的插槽。同样,这是一个开销,因为布尔值通常存储为32位值。
但是有一种更便宜的方式来存储布尔值:作为整数的打包位。这就是java.util.BitSet
所做的,所以每个布尔值都会占用一位。
使用BitSet
解决方案并跟踪可用的数量:
public class RandomNumbers {
private final Random random = new Random();
private final BitSet used = new BitSet();
private final int min = 10000;
private final int max = 99999;
private final int numbersAvailable = max - min + 1;
public static void main (String[] args) {
RandomNumbers randomNumbers = new RandomNumbers();
for (int i = 0; i < 100; i++) {
System.out.println(randomNumbers.nextRandom());
}
}
public int nextRandom () throws NoSuchElementException {
while (numbersAvailable > 0) {
int rnd = min + random.nextInt(max - min + 1);
if (!used.get(rnd)) {
used.set(rnd);
numbersAvailable--;
return rnd;
}
}
throw new NoSuchElementException();
}
}
答案 2 :(得分:5)
只需
(int)(Math.random()*89999)+10000
编辑后:(编辑前没有理解) - 你可以将生成的数字放在HashSet
中,然后随机检查一下是否包含新编号(如果你多次使用它会很慢,但是我如果你不需要很多数字,我认为这是一个很好的解决方案。
从我的评论中:在大约50%的数字出来之后,我会创建一个剩余数字的集合,与你的相同,但是你应该在课堂上记录,它可以在50%的结果使用后冻结片刻并给出能够将此因素设置为客户。
根据“生成数字中必须有多少随机性”(例如序列生成器的数学方法),可能是更好的方法
答案 3 :(得分:4)
看起来很简单。一个更简单的解决方案,内存使用量更少,只需创建一个包含所需数字的集合,如下所示:
Random random = new Random();
Set<Integer> randomNumbers = new HashSet<Integer>(10);
while(randomNumbers.size() < 10)
randomNumbers.add( new Integer(random.nextInt(89999) + 10000) );
并查看所有内容:
for(Integer randomNumber : randomNumbers){
System.out.println(randomNumber);
}
这将保证集合属性的唯一性,并大大提高您的内存使用率。
答案 4 :(得分:1)
您的方法确实非常适合创建大量唯一值,但是如果您只创建少量唯一值,那么简单地跟踪使用的值以保证唯一性会更有效
import java.util.Collection;
import java.util.HashSet;
import java.util.Random;
public class UniqueRandom {
static Random rnd=new Random();
public static void main(String args[]){
Collection<Integer> alreadyChosen = new HashSet<Integer>();
for(int i=0;i<10;i++){
System.out.println(getNextUniqueRandom (alreadyChosen));
}
}
public static int getNextUniqueRandom(Collection<Integer> alreadyChosen){
if (alreadyChosen.size()==90000){ //hardcoded 5 figure numbers, consider making a variable
throw new RuntimeException("All 5 figure IDs used");
}
boolean unique=false;
int value=0;
while(unique==false){
value=rnd.nextInt(90000)+10000;
unique=!alreadyChosen.contains(value);
}
alreadyChosen.add(value);
return value;
}
}
当只需要一小部分可用范围时,这种方法非常有效,但随着碰撞变得更加普遍,这种方法变得越来越慢。您应该选择的确切实现在很大程度上取决于您需要获得多少值。