Creating random numbers with no duplicates

后端 未结 18 1674
忘了有多久
忘了有多久 2020-11-21 12:00

In this case, the MAX is only 5, so I could check the duplicates one by one, but how could I do this in a simpler way? For example, what if the MAX has a value of 20? Thanks

相关标签:
18条回答
  • 2020-11-21 12:10

    The most easy way is use nano DateTime as long format. System.nanoTime();

    0 讨论(0)
  • 2020-11-21 12:11

    Another approach which allows you to specify how many numbers you want with size and the min and max values of the returned numbers

    public static int getRandomInt(int min, int max) {
        Random random = new Random();
    
        return random.nextInt((max - min) + 1) + min;
    }
    
    public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
            int max) {
        ArrayList<Integer> numbers = new ArrayList<Integer>();
    
        while (numbers.size() < size) {
            int random = getRandomInt(min, max);
    
            if (!numbers.contains(random)) {
                numbers.add(random);
            }
        }
    
        return numbers;
    }
    

    To use it returning 7 numbers between 0 and 25.

        ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("" + list.get(i));
        }
    
    0 讨论(0)
  • 2020-11-21 12:13

    This would be a lot simpler in java-8:

    Stream.generate(new Random()::ints)
                .distinct()
                .limit(16) // whatever limit you might need
                .toArray(Integer[]::new);
    
    0 讨论(0)
  • 2020-11-21 12:13

    There is algorithm of card batch: you create ordered array of numbers (the "card batch") and in every iteration you select a number at random position from it (removing the selected number from the "card batch" of course).

    0 讨论(0)
  • 2020-11-21 12:14

    Your problem seems to reduce to choose k elements at random from a collection of n elements. The Collections.shuffle answer is thus correct, but as pointed out inefficient: its O(n).

    Wikipedia: Fisher–Yates shuffle has a O(k) version when the array already exists. In your case, there is no array of elements and creating the array of elements could be very expensive, say if max were 10000000 instead of 20.

    The shuffle algorithm involves initializing an array of size n where every element is equal to its index, picking k random numbers each number in a range with the max one less than the previous range, then swapping elements towards the end of the array.

    You can do the same operation in O(k) time with a hashmap although I admit its kind of a pain. Note that this is only worthwhile if k is much less than n. (ie k ~ lg(n) or so), otherwise you should use the shuffle directly.

    You will use your hashmap as an efficient representation of the backing array in the shuffle algorithm. Any element of the array that is equal to its index need not appear in the map. This allows you to represent an array of size n in constant time, there is no time spent initializing it.

    1. Pick k random numbers: the first is in the range 0 to n-1, the second 0 to n-2, the third 0 to n-3 and so on, thru n-k.

    2. Treat your random numbers as a set of swaps. The first random index swaps to the final position. The second random index swaps to the second to last position. However, instead of working against a backing array, work against your hashmap. Your hashmap will store every item that is out of position.

    int getValue(i) { if (map.contains(i)) return map[i]; return i; } void setValue(i, val) { if (i == val) map.remove(i); else map[i] = val; } int[] chooseK(int n, int k) { for (int i = 0; i < k; i++) { int randomIndex = nextRandom(0, n - i); //(n - i is exclusive) int desiredIndex = n-i-1; int valAtRandom = getValue(randomIndex); int valAtDesired = getValue(desiredIndex); setValue(desiredIndex, valAtRandom); setValue(randomIndex, valAtDesired); } int[] output = new int[k]; for (int i = 0; i < k; i++) { output[i] = (getValue(n-i-1)); } return output; }

    0 讨论(0)
  • 2020-11-21 12:15

    It really all depends on exactly WHAT you need the random generation for, but here's my take.

    First, create a standalone method for generating the random number. Be sure to allow for limits.

    public static int newRandom(int limit){
        return generatedRandom.nextInt(limit);  }
    

    Next, you will want to create a very simple decision structure that compares values. This can be done in one of two ways. If you have a very limited amount of numbers to verify, a simple IF statement will suffice:

    public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
        boolean loopFlag = true;
        while(loopFlag == true){
            if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
                int1 = newRandom(75);
                loopFlag = true;    }
            else{
                loopFlag = false;   }}
        return int1;    }
    

    The above compares int1 to int2 through int5, as well as making sure that there are no zeroes in the randoms.

    With these two methods in place, we can do the following:

        num1 = newRandom(limit1);
        num2 = newRandom(limit1);
        num3 = newRandom(limit1);
        num4 = newRandom(limit1);
        num5 = newRandom(limit1);
    

    Followed By:

            num1 = testDuplicates(num1, num2, num3, num4, num5);
            num2 = testDuplicates(num2, num1, num3, num4, num5);
            num3 = testDuplicates(num3, num1, num2, num4, num5);
            num4 = testDuplicates(num4, num1, num2, num3, num5);
            num5 = testDuplicates(num5, num1, num2, num3, num5);
    

    If you have a longer list to verify, then a more complex method will yield better results both in clarity of code and in processing resources.

    Hope this helps. This site has helped me so much, I felt obliged to at least TRY to help as well.

    0 讨论(0)
提交回复
热议问题