【问题标题】:How can I prevent the overlapping random numbers如何防止重叠的随机数
【发布时间】:2015-01-20 05:31:15
【问题描述】:

如何防止随机数中的重复数字。 我需要在 1 和 9 之间生成 5 个不同的数字。 我经常会得到相同的数字,例如 23334,我该如何防止呢? 任何帮助都会很棒!

    int num2 = (int) Math.round((Math.random()*9) +1);
    int num1 = (int) Math.round((Math.random()*9) +1);
    int num5 = (int) Math.round((Math.random()*9) +1);
    int num3 = (int) Math.round((Math.random()*9) +1);
    int num4 = (int) Math.round((Math.random()*9) +1);

【问题讨论】:

  • 添加到集合.
  • 仅供参考:如果您的范围只有 1-9,那么您应该期望使用随机数。你很有可能会得到重复。
  • 对于小范围的小集合,排列可能是最好的。对于大范围,您可以创建一组已选择的值并根据需要重试。对于需要有界最坏情况行为的大范围,您需要在 [1,m], [1,m-1], ... [1,m-n+1] 中选择 n 个不同的随机值,然后执行修复。

标签: java random


【解决方案1】:

一种选择是使用 shuffle 算法(例如 Fisher-Yates shuffle )生成从 1 到 9 的随机序列,然后取序列的前 5 个数字

关于 StackOverflow 的进一步解释:https://stackoverflow.com/a/196065/950427

【讨论】:

  • 我怀疑生成序列 1-N,如果您需要 0-1000000 中的 5 个,随机查找随机 5 会更有效
  • 您可以修改Fisher-Yates shuffle算法,在找到前5个数字后立即停止算法
  • 但无论如何我必须分配内存(一个数组)来生成序列?
  • wiki 页面中的算法有一个“由内而外”的变体,其中 shuffle 不会修改源数组,因此不需要预先分配源数组,并且可以改用简单索引。我会尝试发布示例代码
  • 对于常见情况,当然您需要一些详细的解决方案,但如果您只能在屏幕上显示有限列表中的 5 个元素,最好使用 faster to implementation 而不是 在普通情况下更有效方法
【解决方案2】:
Set<Integer> set=new HashSet<>();
while (set.size()<5) {
    set.add( Math.round((Math.random()*9) +1));
}

集满后,您有 5 个唯一的随机数。

更新:只是为了说明 Jared Burrows 的评论

【讨论】:

  • 必须喜欢具有无限时间的最坏情况复杂性的解决方案 :)
  • @Kon 发表你自己的答案。
  • @JaredBurrows Phuong 在我看来,上面已经发布了一个更好的答案。不用我重复了。
  • @Kon 我同意这不是最佳的,但对于固定数字就足够了。如果问题要求在 0-K 范围内生成 N 个唯一数字,那么答案肯定是不同的。
  • @Kon - 对于大约 10 个选择的样本空间,是的,但您认为哪个答案最适合大型样本空间?
【解决方案3】:
  1. 创建列表包括您想要的数字(1 到 9)。
  2. 生成从 0 到(列表大小减 1)的随机数。
  3. 从上面生成的随机数中按索引删除一个元素。并将删除的元素添加到要作为结果返回的数组中

    public static void main(String[] args) {
         int []answers= returnRandomNonRepeatingNumbers(5,0,9);
         for(int answer: answers) {
            System.out.println(answer);
         }
    }
    public static int[] returnRandomNonRepeatingNumbers(int sizeYouWant, int poolStart, int poolEnd) {
        List<Integer> pool=new ArrayList<Integer>();
        for(int i=poolStart;i<=poolEnd;i++) {
           pool.add(i);
        }
    
        int []answers=new int[sizeYouWant];
    
        for(int i=0;i<sizeYouWant;i++) {
            //random index to be pick and remove from pool
            int randomIndex = (int) Math.round((Math.random()*(pool.size()-1)));
            answers[i]=pool.remove(randomIndex);
        }
    
        return answers;
    }
    

【讨论】:

    【解决方案4】:

    如果可能的随机值的数量很少,你想使用 shuffle。

    List<Integer> values = IntStream.range(0, 10).boxed().collect(toList());
    Collections.shuffle(values);
    values = values.subList(0, 5);
    

    如果可能的随机值的数量很大,您想测试将它们添加到 Set(如果足够小,则添加到原始列表)

    Set<Integer> valueSet = new HashSet<>(); 
    Random rand = new Random();
    while(valuesSet.size() < 5) valuesSet.add(rand.nextInt(9) + 1);
    List<Integer> values = new ArrayList<>(valueSet);
    Collections.shuffle(values, rand);
    

    注意:您需要洗牌,因为它不保留顺序。例如数字 1,2,3 将始终以 HashSet 的顺序出现,而不是 3,2,1。

    【讨论】:

      【解决方案5】:

      Floyd's subset selection algorithm 旨在完全满足您的需求,即使对于大型集合也非常高效。从一组n 中选择m 项目是O(m) 的平均运行时间,独立于n。这是一个 Java 实现。

      /*
       * Floyd's algorithm to chose a random subset of m integers
       * from a set of n, zero-based.
       */
      public static HashSet<Integer> generateMfromN(int m, int n) {
         HashSet<Integer> s = new HashSet<Integer>();
         for (int j = n-m; j < n; ++j) {
            if(! s.add((int)((j+1) * Math.random()))) {
               s.add(j);
            }
         }
         return s;
      }
      

      【讨论】:

        【解决方案6】:

        解决此问题的一种可能方法是分而治之。以下步骤描述了该方法:

        1. m 是最小值,n 是最大值,在我想要得到 x 随机数的范围内
        2. mn 之间选择一个随机的 p。将其保存到答案数组中。当我们得到问题的一个答案时,将 x 减少 1
        3. 现在取一个 q 一个介于 mp-1 之间的随机数,另一个 r 一个随机数在 p+1n 之间。用 qr 填充答案数组,q 减少 x 1, 减少 1 r
        4. 现在递归地进行这个过程,直到下限 (m) 和上限 (n) 相等或 x 变为 0。

        好处:这种方法的好处是,在最坏的情况下,它的运行时间将是 O(x),其中 x 是需要的随机数个数。最好的情况也是 o(x),因为我必须找到至少 n 个随机数。这两个构成了 θ(x) 复杂度的平均情况。

        import java.util.Random;
        class GenerateDistinctRandom{
        static int alreadyPut = 0;
        static Random rand = new Random();
        
            public static int[] generateDistinctRandom(int howMany, int rangeMin, int rangeMax)
            {
                int randomNumbers[] = new int[howMany]; 
                GenerateDistinctRandom.recursiveRandomGenerator(rangeMin, rangeMax, randomNumbers, howMany);
                return randomNumbers;
            }
        
            private static void recursiveRandomGenerator(int rangeMin, int rangeMax, int[] storage ,int storageSize)
            {
                if(rangeMax - rangeMin <= 0 || GenerateDistinctRandom.alreadyPut == storageSize)
                {
                    return ;
                }
        
            int randomNumber = GenerateDistinctRandom.rand.nextInt(rangeMax-rangeMin) + rangeMin;
            storage[GenerateDistinctRandom.alreadyPut] = randomNumber;
            GenerateDistinctRandom.alreadyPut++;
        
            //calling the left side of the recursion
            recursiveRandomGenerator(rangeMin, randomNumber - 1, storage, storageSize);
            recursiveRandomGenerator(randomNumber + 1, rangeMax, storage, storageSize);     
            }
        
            public static void main(String []args){
                int howMany = 5;
                int distinctNumber[] = GenerateDistinctRandom.generateDistinctRandom(howMany 0, 9);
        
                for(int i = 0;i < howMany;i++)
                {
                    System.out.println(distinctNumber[i]);
                }
        
            }
        }
        

        【讨论】:

          【解决方案7】:

          我想您需要将已生成的那些存储到一个数组中,并将新的随机数与列表进行比较以确保它是唯一的。

          public static void main (String[] args) throws java.lang.Exception
          {
              // your code goes here
              int[] numbers = new int[5];
              int tempNumber = 0;
          
              for(int numberCounter = 0; numberCounter < numbers.length;)
              {
                  tempNumber = (int) Math.round((Math.random()*9) +1);
          
                  if(!contains(numbers, tempNumber)){
                      numbers[numberCounter++] = tempNumber;
                  }
              }
          }
          
          public static boolean contains(final int[] numbersArray, final int tempNumber) {
              for (final int numberFromArray : numbersArray) {
                  if (numberFromArray == tempNumber) {
                      return true;
                  }
              }
              return false;
          } 
          

          我注意到您在示例中没有使用数组,所以如果您还不知道如何使用它们,您也可以创建 5 个变量。

          int randomNumber = 0;
          
          int firstNumber = Math.round((Math.random()*9) +1);
          int secondNumber = 0;
          
          while(secondNumber == 0){
              randomNumber = Math.round((Math.random()*9) +1)l
              if(randomNumber != firstNumber){
                  secondNumber = randomNumber;
              }
          }
          

          你可以继续做这样的 while 语句。但是,如果您应该了解数组,则绝对应该使用数组来存储数字。

          【讨论】:

            【解决方案8】:

            这个怎么样?

            package com.se;
            
            import java.util.ArrayList;
            import java.util.List;
            import java.util.Random;
            
            public class TestRandom {
            
                List<Integer> comp = new ArrayList<>();
                int listSize = 20;
                public void doTask() {
            
                    Random ran = new Random();
                    int i = 0;
                    while(i < listSize){
                        int randomNumber = ran.nextInt(80) + 1;
            
                        if(!comp.contains(randomNumber)){
                           comp.add(randomNumber);
                           i++;
                        }
                    }
            
                for(Integer num : comp){
                    System.out.println(num);
                }
            }
            
            public static void main(String[] args) {
                TestRandom testRandom = new TestRandom();
                testRandom.doTask();
            }
            
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-12-25
              • 2014-01-01
              • 2017-05-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多