简体   繁体   English

使用复杂度为O(n)的唯一随机数填充大小为n的Java数组

[英]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). 我必须编写代码来填充大小为n的数组,其中包含0-10n (含)范围内的唯一随机数。 I can do it with O(n^2) complexity but I need to do it with O(n) complexity. 我可以用O(n^2)复杂度做到这一点,但我需要用O(n)复杂度来做。 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: 作为参考,这是我的方法的O(n^2)版本:

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) 生成范围内所有数字的列表 - O(n)

  2. Shuffle the list - O(n) 洗牌清单 - O(n)

  3. Extract the first N items from the list - O(1) or O(n) 从列表中提取前N个项目 - O(1)或O(n)

Therefore the entire operation would be O(n). 因此整个操作将是O(n)。

To shuffle the entire list in O(n), you could use Fisher-Yates shuffle : 要在O(n)中对整个列表进行洗牌,您可以使用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). 作为奖励,它已经在Collections.shuffle() (文档提到它在线性时间运行)。

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. 保留已输入的一Set条目。 For each candidate check whether the Set already contains the entry. 对于每个候选人,检查Set是否已包含该条目。 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. 如果没有,将它添加到数组和Set (假设您的检查没有同时添加到Set ),否则生成一个新的候选。 Repeat for each candidate until you succeed, then proceed to the next open slot in the array. 重复每个候选人,直到成功,然后继续到阵列中的下一个打开的插槽。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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