简体   繁体   中英

fill an array in Java of size n with unique random numbers with complexity O(n)

I have to write code to fill an array of size n with unique random numbers in the range 0-10n (inclusive). I can do it with O(n^2) complexity but I need to do it with O(n) complexity. I can't think of a way to do it that doesn't involve generating the random number, then going back through the partly filled array to check whether there are duplicates in the array.

For reference, here's my O(n^2) version of the method:

private static void fillWithUniqueN2(int[] numbers) 
{
    Random rng = new Random();
    for (int i = 0; i < numbers.length; i++)
    {
        boolean added = false;
        while (!added)
        {
            int newNumber = rng.nextInt(numbers.length);
            boolean unique = true;

            for (int j = 0; j < i; j++)
            {
                if (newNumber == numbers[j])
                {
                    unique = false;
                }
            }

            if (unique)
            {
                numbers[i] = newNumber;
                added = true;
            }   
        }       
    }
}

The standard solution for generating unique random numbers within a range is to:

  1. Generate a list of all the numbers within the range - O(n)

  2. Shuffle the list - O(n)

  3. Extract the first N items from the list - O(1) or O(n)

Therefore the entire operation would be O(n).

To shuffle the entire list in O(n), you could use Fisher-Yates shuffle :

-- To shuffle an array a of n elements (indices 0..n-1):
for i from 0 to n−2 do
     j ← random integer such that i ≤ j < n
     exchange a[i] and a[j]

As a bonus, it's already implemented in Collections.shuffle() (the doc mentions it runs in linear time).

package stackOverflow;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


public class FisherYates
{
    public static void main(String[] args) {
        int n = 10;
        IntStream range = IntStream.rangeClosed(0, n * 10);
        List<Integer> integers = range.boxed().collect(Collectors.toList());
        Collections.shuffle(integers);
        System.out.println(integers.subList(0, n));
    }
}

As an example, it outputs :

[28, 44, 26, 94, 21, 65, 55, 25, 99, 93]
[40, 57, 3, 42, 61, 26, 64, 45, 19, 41]
...

Keep a Set of entries already entered. For each candidate check whether the Set already contains the entry. If not, add it to the array and to the Set (assuming your check didn't simultaneously add to the Set ), otherwise generate a new candidate. Repeat for each candidate until you succeed, then proceed to the next open slot in the array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM