Creating random numbers with no duplicates

后端 未结 18 1768
忘了有多久
忘了有多久 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:04

    Following code create a sequence random number between [1,m] that was not generated before.

    public class NewClass {
    
        public List<Integer> keys = new ArrayList<Integer>();
    
        public int rand(int m) {
            int n = (int) (Math.random() * m + 1);
            if (!keys.contains(n)) {
                keys.add(n);
                return n;
            } else {
                return rand(m);
            }
        }
    
        public static void main(String[] args) {
            int m = 4;
            NewClass ne = new NewClass();
            for (int i = 0; i < 4; i++) {
                System.out.println(ne.rand(m));
            }
            System.out.println("list: " + ne.keys);
        }
    }
    
    0 讨论(0)
  • 2020-11-21 12:05

    The most efficient, basic way to have non-repeating random numbers is explained by this pseudo-code. There is no need to have nested loops or hashed lookups:

    // get 5 unique random numbers, possible values 0 - 19
    // (assume desired number of selections < number of choices)
    
    const int POOL_SIZE = 20;
    const int VAL_COUNT = 5;
    
    declare Array mapping[POOL_SIZE];
    declare Array results[VAL_COUNT];
    
    declare i int;
    declare r int;
    declare max_rand int;
    
    // create mapping array
    for (i=0; i<POOL_SIZE; i++) {
       mapping[i] = i;
    }
    
    max_rand = POOL_SIZE-1;  // start loop searching for maximum value (19)
    
    for (i=0; i<VAL_COUNT; i++) {
        r = Random(0, max_rand); // get random number
        results[i] = mapping[r]; // grab number from map array
        mapping[r] = max_rand;  // place item past range at selected location
    
        max_rand = max_rand - 1;  // reduce random scope by 1
    }
    

    Suppose first iteration generated random number 3 to start (from 0 - 19). This would make results[0] = mapping[3], i.e., the value 3. We'd then assign mapping[3] to 19.

    In the next iteration, the random number was 5 (from 0 - 18). This would make results[1] = mapping[5], i.e., the value 5. We'd then assign mapping[5] to 18.

    Now suppose the next iteration chose 3 again (from 0 - 17). results[2] would be assigned the value of mapping[3], but now, this value is not 3, but 19.

    This same protection persists for all numbers, even if you got the same number 5 times in a row. E.g., if the random number generator gave you 0 five times in a row, the results would be: [ 0, 19, 18, 17, 16 ].

    You would never get the same number twice.

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

    There is another way of doing "random" ordered numbers with LFSR, take a look at:

    http://en.wikipedia.org/wiki/Linear_feedback_shift_register

    with this technique you can achieve the ordered random number by index and making sure the values are not duplicated.

    But these are not TRUE random numbers because the random generation is deterministic.

    But depending your case you can use this technique reducing the amount of processing on random number generation when using shuffling.

    Here a LFSR algorithm in java, (I took it somewhere I don't remeber):

    public final class LFSR {
        private static final int M = 15;
    
        // hard-coded for 15-bits
        private static final int[] TAPS = {14, 15};
    
        private final boolean[] bits = new boolean[M + 1];
    
        public LFSR() {
            this((int)System.currentTimeMillis());
        }
    
        public LFSR(int seed) {
            for(int i = 0; i < M; i++) {
                bits[i] = (((1 << i) & seed) >>> i) == 1;
            }
        }
    
        /* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
        public short nextShort() {
            //printBits();
    
            // calculate the integer value from the registers
            short next = 0;
            for(int i = 0; i < M; i++) {
                next |= (bits[i] ? 1 : 0) << i;
            }
    
            // allow for zero without allowing for -2^31
            if (next < 0) next++;
    
            // calculate the last register from all the preceding
            bits[M] = false;
            for(int i = 0; i < TAPS.length; i++) {
                bits[M] ^= bits[M - TAPS[i]];
            }
    
            // shift all the registers
            for(int i = 0; i < M; i++) {
                bits[i] = bits[i + 1];
            }
    
            return next;
        }
    
        /** returns random double uniformly over [0, 1) */
        public double nextDouble() {
            return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
        }
    
        /** returns random boolean */
        public boolean nextBoolean() {
            return nextShort() >= 0;
        }
    
        public void printBits() {
            System.out.print(bits[M] ? 1 : 0);
            System.out.print(" -> ");
            for(int i = M - 1; i >= 0; i--) {
                System.out.print(bits[i] ? 1 : 0);
            }
            System.out.println();
        }
    
    
        public static void main(String[] args) {
            LFSR rng = new LFSR();
            Vector<Short> vec = new Vector<Short>();
            for(int i = 0; i <= 32766; i++) {
                short next = rng.nextShort();
                // just testing/asserting to make 
                // sure the number doesn't repeat on a given list
                if (vec.contains(next))
                    throw new RuntimeException("Index repeat: " + i);
                vec.add(next);
                System.out.println(next);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-21 12:08

    Instead of doing all this create a LinkedHashSet object and random numbers to it by Math.random() function .... if any duplicated entry occurs the LinkedHashSet object won't add that number to its List ... Since in this Collection Class no duplicate values are allowed .. in the end u get a list of random numbers having no duplicated values .... :D

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

    Here is an efficient solution for fast creation of a randomized array. After randomization you can simply pick the n-th element e of the array, increment n and return e. This solution has O(1) for getting a random number and O(n) for initialization, but as a tradeoff requires a good amount of memory if n gets large enough.

    0 讨论(0)
  • 2020-11-21 12:10
    //random numbers are 0,1,2,3 
    ArrayList<Integer> numbers = new ArrayList<Integer>();   
    Random randomGenerator = new Random();
    while (numbers.size() < 4) {
    
        int random = randomGenerator .nextInt(4);
        if (!numbers.contains(random)) {
            numbers.add(random);
        }
    }
    
    0 讨论(0)
提交回复
热议问题