[英]Generating many random numbers within a range with some exceptions in java
我需要在一個范圍內生成大量隨機數,但有一些例外。 現在我打算這樣做,
public class Main
{
static List<Integer> except = Arrays.asList(5, 6, 11, 12, 17, 18, 23, 25, 28, 29);
public static void main(String[] args) {
List<Integer> randomNums = new ArrayList<>();
Random random = new Random();
int z;
for(i=0; i<20; i++) {
z = random.nextInt(30);
while(except.contains(z)) z = random.nextInt(30);
randomNums.add(z);
}
System.out.println(randomNums);
}
}
在我的情況下,“except”和“randomNums”的大小會高得多。 所以代碼會花很多時間來避免我不想要的數字。
我很想知道我可以加速我的代碼嗎? 如果我可以刪除 while 循環,那么它肯定會是一個 O(n)。 但我怎么能做到這一點。 謝謝。
我的建議是你做你要做的希望在您的結果號碼列表,每次挑選從該列表中隨機成員。 它需要一些初始化,但之后你的循環應該運行得很快。
int maxExclusive = 30;
Integer[] baseArr = new Integer[maxExclusive];
Arrays.setAll(baseArr, Integer::valueOf);
List<Integer> base = new ArrayList<>(Arrays.asList(baseArr));
base.removeAll(except);
List<Integer> randomNums = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < 20; i++) {
Integer z = base.get(random.nextInt(base.size()));
randomNums.add(z);
}
System.out.println(randomNums);
示例輸出:
[1, 10, 27, 2, 24, 22, 7, 8, 0, 27, 19, 27, 15, 14, 21, 22, 13, 24, 2, 13]
這是一種方法:
public static void main(String[] args) {
final int exceptMin = 5;
final int exceptMax = 29;
Set<Integer> except = new HashSet<>(
Arrays.asList(5, 6, 11, 12, 17, 18, 23, 25, 28, 29)
);
List<Integer> safeValues = getSafeValues(except, exceptMin, exceptMax);
List<Integer> randomValues = getRandomValues(except, safeValues);
}
public static List<Integer> getSafeValues(Set<Integer> except, int exceptMin, int exceptMax) {
List<Integer> safeValues = new ArrayList<>();
for(int i = exceptMin; i < exceptMax; i++) {
if(!except.contains(i))
safeValues.add(i);
}
return safeValues;
}
public static List<Integer> getRandomValues(Set<Integer> except, List<Integer> safeValues) {
List<Integer> randomValues = new ArrayList<>();
for(int i = 0; i < 800_0000; i++) {
int randomNumber = getRandomValue(except, safeValues);
randomValues.add(randomNumber);
}
return randomValues;
}
public static int getRandomValue(Set<Integer> except, List<Integer> safeValues) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int randomNumber = random.nextInt(0, 30);
if(except.contains(randomNumber)) {
int randomIndex = random.nextInt(safeValues.size());
randomNumber = safeValues.get(randomIndex);
}
return randomNumber;
}
因此,只需使用另一個存儲可安全使用的值的列表,並在隨機生成的值失敗時選擇其中一個。 正如@vanje 已經提到的,它使用 HashSet 來執行查找,因為它具有恆定的時間復雜度( https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html )。
這種方法(在我的機器上)執行如下:
generated Numbers time in ms
800_000 300
400_000 156
200_000 87
100_000 38
我使用了您的答案中指定的例外情況,並生成了 0(含)和 30(不含)之間的數字,因此有很多“未命中”。
但是,這種方法會比生成“新鮮”隨機值花費更多的內存,並且需要一些准備。 例如,當異常為{0, 100_0000}
您將生成大量“安全”數字。 您可以將safeNumbers
列表拆分為多個列表來處理該問題。 除此之外,這種方法可能會破壞隨機數的分布(如果這對您來說是個問題)。
編輯:當我寫這個答案時,我沒有意識到@Ole VV 也使用了這種方法。 如果需要,我將刪除此答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.