【问题标题】:Generating unique random numbers [duplicate]生成唯一的随机数[重复]
【发布时间】:2014-07-01 11:06:48
【问题描述】:

如何生成 9 个 1 到 9 之间的随机数,不重复,一个接一个。就像是: 假设生成的第一个随机数是 4,那么下一个随机数必须在 [1, 9] - {4} 中。 我的第一种方法是将每个随机生成的数字添加到一个集合中,从而避免重复。但在更糟糕的情况下,比如我们已经生成了 6 个并且我们必须再生成 3 个数字,这个过程会有点慢。而当范围从 [1, 9] 更改为 [1, 1000] 时,这种方法听起来并不正确。 谁能建议一种替代方法。

【问题讨论】:

  • 您可以将刚刚选择的数字与末尾的数字交换,并假设在下一步中您将从一个元素短的数组中进行选择。
  • 生成一个数字并计算其frequency..如果frequency > 0 生成另一个随机数和addsubtract 或做一些数学运算以获得另一个数字..尽管这也将是非常忙碌的工作
  • 您需要生成一个排列并从排列中选择。如果您可以将其全部保留在内存中,请随机播放
  • 生成数组:int set[9]={1,2,3,4,5,6,7,8,9} 并在循环中 for(i=0;i 这是 O(N) 我认为是可以接受的

标签: java algorithm random


【解决方案1】:

从一个排序数组开始(很容易通过 for 循环创建);然后随机播放,将每个数组元素与另一个(随机选择的)元素交换。 为避免 cmets 中讨论的偏差,其他元素的索引必须等于或高于第一个元素的索引。 如果索引相等,则不交换元素。 (这个答案的原始版本包含一个关于元素被交换回来的可能性的句子,但现在已经过时了,因为突出显示的修改不会再发生这种情况)

【讨论】:

  • 其实这个看似正确的算法actually shuffles nonrandomly.
  • 要获得无偏见的随机播放,您需要确保仅将每个元素与随机选择的 later 元素或自身交换(即不交换)。跨度>
  • @j_random_hacker:哇,谢谢你的信息!
  • 不客气 :) 这不是一个大的变化,所以如果你更新你的答案,我会 +2。
【解决方案2】:

如果您对自己实现一个算法来做您想做的事情不感兴趣,您可以使用一种已经在 J​​ava 库中实现的简单方法。

您可以创建Integer 的集合(已排序的List)(startend,其中start=1end=9 在您的示例中),然后使用方法Collections.shuffle(list);,比如这样:

static List<Integer> randArray(int start, int end) { //specify start/end
    List<Integer> randList=new ArrayList<>(end-start+1); //create list
    for (int k=start;k<=end;k++) { //generate integers in order
        randList.add(k); //add integers to the list
    }        
    Collections.shuffle(randList); //reoder randomly the list
    return randList; //return the list with items in random order
}

shuffle 方法只是随机地重新排序列表中的项目。

【讨论】:

  • 是的,它可以工作......虽然现在我更想知道 Collections.shuffle() 是如何工作的。
【解决方案3】:

以下是两种可能的方法:-

方法一:-

  1. 将所有数字放在一个大小为 n 的数组中。
  2. 随机选择一个数字和索引 i = rand(0,size)
  3. 打印 arr[i]
  4. 交换 arr[i] 和 arr[size-1]
  5. 大小 = 大小 -1
  6. 重复 1 到 5 直到列表用完。

时间复杂度: O(N)

空间复杂度: O(N)

方法二:-

  1. 选择池大小为 K。
  2. 生成 K 个随机整数。
  3. 将它们显示为前 k 个结果。
  4. 将它们添加到哈希集。
  5. 为池中所有先前的整数添加所有 ak+1。
  6. 如果不在hashset中就加1。
  7. 从池中随机选择一个整数 r 并显示出来。
  8. 如果不在哈希集中,则将 r+1 添加到池中
  9. 做 7 到 8 次直到池用完。

时间复杂度: O(N)

空间复杂度: O(K)

优点和缺点:-

方法一:对于小整数范围使用此方法,因为它需要更大的空间,但它非常快速且随机。

方法 2: 将此方法用于更大的范围,因为它需要您选择的内存 O(K)。 k越高,生成的数字的随机性就越高。因此,您可以在保持良好速度的同时在空间和随机性之间取得良好的平衡。

【讨论】:

    【解决方案4】:

    像这样创建一个 ArrayList:

    索引 0->索引 1->索引 2...

    [1] -> [2] -> [3]....

    在0和list.size()之间生成一个随机索引值,获取list中的位置:

    yourNumberResult = get(randomIndexValue)。

    然后删除列表中的位置:

    list.remove(randomIndexValue)

    然后在迭代中重复这个直到 list.size()==0

    【讨论】:

    • 请注意,从 ArrayList 中删除项是低效的,因为删除后的所有项都必须向下移动以填补空白。在大型阵列上重复执行此操作会导致大量内存流量,这可能会成为瓶颈。
    • 我猜交换而不是删除会更快,但是是的,感谢算法
    • 我不知道,因为交换算法非常复杂。我认为对于
    【解决方案5】:

    使用Java 8,Enne的方法可以这样写:

    private static List<Integer> generateRandom( int low, int high )
    {
        List<Integer> range = IntStream.range( low, high ).boxed()
                                       .collect( Collectors.toList() );
    
        Collections.shuffle( range );
        return range;
    }
    

    【讨论】:

    • 我现在没有使用 Java 8,但这绝对有帮助 :)
    【解决方案6】:

    按排序顺序为数字 1 到 9 生成一个数组。

    int arr[]=new int[9];
    for(int i=0;i<9;i++)
       arr[i]=i+1;
    

    现在shuffle 给定数组。

    如何洗牌?

    To shuffle an array a of n elements (indices 0..n-1):
       for i from n - 1 downto 1 do
           j = random integer with 0 <= j <= i
           exchange a[j] and a[i]
    

    参考文献

    http://www.geeksforgeeks.org/shuffle-a-given-array/

    【讨论】:

    • 是的...刚刚得到这个算法 ->Fisher-Yates_shuffle
    • 是的,这个会以等概率随机生成从 1 到 9 的数字。
    【解决方案7】:
    public ArrayList<Integer> getRandom(int numbers,int min_value, int max_value)
    {     
        HashSet<Integer> list = new HashSet<>();
        Random r = new Random();
        while (list.size()<numbers) {
            list.add(r.nextInt(max_value - min_value) + min_value);
        }
        return new ArrayList<>(list);
    }
    

    替代方案:

    public ArrayList<Integer> getRandom(int numbers,int min_value, int max_value)
    {     
        Random r = new Random();
        ArrayList<Integer> list = new ArrayList<>();
        for(int i=min_value; i<=max_value;i++)
            list.add(i);
        while (list.size()>numbers) {
           list.remove(r.nextInt(list.size()));
        }
        Collections.shuffle(list);
        return list;
    }
    

    替代方案:

       public ArrayList<Integer> getRandom(int numbers, int min_value, int max_value) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = min_value; i <= max_value; i++) {
            list.add(i);
        }
        Collections.shuffle(list);
        return new ArrayList<>(list.subList(0, numbers));
    }
    

    【讨论】:

    • 谢谢...这三种算法都有效。尽管正如我所提到的,在第一种方法中,随着越来越多的数字被填充到 HashSet 中,list.add() 会使过程变慢,因为会一次又一次地生成相同的随机数。这会影响算法的效率。此外,正如其他 cmets 中所述,list.remove() 方法效率低下,因为每次删除数字以填补空白时都必须移动数字。我猜Fisher-Yates_shuffle 是一种类似于 Collections.shuffle() 的算法。
    猜你喜欢
    • 2016-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-13
    相关资源
    最近更新 更多