簡體   English   中英

java - 在一個范圍內生成許多隨機數,但在java中有一些例外

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM