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

时间:2017-02-27 19:50:21

标签: java arrays algorithm

我必须编写代码来填充大小为n的数组,其中包含0-10n(包括)范围内的唯一随机数。我可以使用O(n^2)复杂度执行此操作,但我需要以O(n)复杂度执行此操作。我无法想出一种方法,它不涉及生成随机数,然后返回部分填充的数组以检查数组中是否有重复。

供参考,这是我的方法的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;
            }   
        }       
    }
}

3 个答案:

答案 0 :(得分:2)

在一个范围内生成唯一随机数的标准解决方案是:

  1. 生成范围内所有数字的列表 - O(n)

  2. 随机播放列表 - O(n)

  3. 从列表中提取前N个项目 - O(1)或O(n)

  4. 因此整个操作将是O(n)。

答案 1 :(得分:1)

要在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]

作为奖励,它已在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));
    }
}

例如,它输出:

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

答案 2 :(得分:-3)

保留已输入的Set个条目。对于每个候选人,检查Set是否已包含该条目。如果没有,请将其添加到数组和Set(假设您的检查没有同时添加到Set),否则生成新的候选项。重复每个候选人,直到你成功,然后进入阵列中的下一个打开的插槽。