【问题标题】:Limiting duplicate random numbers限制重复的随机数
【发布时间】:2014-03-09 08:35:30
【问题描述】:

我只想知道如何限制随机数出现的次数。我已经生成了 1 到 10 的随机数,并且想限制每个数字出现 4 次。

myArray[i][j] = rand.nextInt(11);

for (int i=0; i < myArray.length; i++) {
   for (int j=0; j < myArray[i].length; j++) {
       myArray[i][j] = rand.nextInt(11);
       System.out.print(" " + myArray[i][j]);

上面的代码创建了随机数。只是想限制他们。

【问题讨论】:

  • 什么是 myArray[][] 维度?)
  • 你调用了多少次 rand.nextInt(11) 即你的数组中有多少个元素?
  • 检查了几种方法here
  • 至少不超过 40 次 :-) 我希望...
  • 我建议使用另一个计数器数组创建一个循环,并在其中创建另一个带有 if 语句的循环,如果某个计数器超过 4,则随机分配另一个数字。

标签: java arrays random


【解决方案1】:

由于您被限制为 10 * 4 = 40 个数字,您可以使用列表并随机化索引:

List<Integer> numbers = new ArrayList<Integer>();
for (int i = 1; i < 11; ++i) {
   for (int j = 0; j < 4; ++j) 
      numbers.add(i);
}

然后当你分配一个随机数时:

int i = rand.nextInt(numbers.size());
myArray[i][j] = numbers.get(i);
numbers.remove(i);

这假设您的二维不会包含超过 40 个数字

【讨论】:

  • 如果您只是 shuffle 列表然后始终删除第一个或最后一个条目,则不需要通过随机索引进行间接寻址。
  • 您只会在创建后随机播放列表,而不是每次迭代。
【解决方案2】:

将生成的 int 的计数存储在数组、Map 或任何东西中怎么样?

Map<Integer, Integer> randomCounts = new HashMap<Integer, Integer>(); 
... your for loops
myArray[i][j] = rand.nextInt(11);
if (randomCounts.containsKey(myArray[i][j])) { 
   randomCounts.put(myArray[i][j],randomCounts.get(myArray[i][j])+1);
} else {
   randomCounts.put(myArray[i][j],1);
}

如果您想检查它们,只需遍历您的地图,然后瞧。 :)

【讨论】:

  • 只要生成值的数量是固定的,我会使用整数数组并执行randomCounts[randomNumber]++ 但仅此一项并不能限制单个数字的重复,它只会记录它。 ..
  • 嗯...感谢您的评论!我选择 Map over arrays,因为这样更容易检查是否有任何数字生成超过 5 次 - randomCounts.containsValue(5) 将代替我工作(但 Collections 也会对数组执行此操作)。 :) 顺便说一句,你为什么要使用数组?
  • 只是因为数组的开销较小。
【解决方案3】:

我的解决方案将结果存储在 arrayList 中:

public class Example {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    final int range = 10;
    int[] numbers = new int[range + 1];
    int sum = 0;
    final int noOfOccurances = 4;
    final int size = range * noOfOccurances;
    Arrays.fill(numbers, 0);
    Random generator = new Random();
    List<Integer> numbersArray = new ArrayList<>();
    while (sum != size) {
        int randomNumber = generator.nextInt(range) + 1;
        if (numbers[randomNumber] != noOfOccurances) {
            numbers[randomNumber]++;
            sum++;
            numbersArray.add(randomNumber);
        }
    }
    System.out.println(numbersArray);
}
}

【讨论】:

  • 很好,我在回复中复制了你的想法
  • @ring0 只有一个循环,你能解释一下为什么复杂度是 O(n²) 吗?
  • 我错了:复杂度是 O(size) - 因为你的程序不起作用 :-) numbers[randomNumber] 永远不会增加,所以 prog 在 size 循环后停止,但你可能会得到 2 1, 5 2,.. 一旦你的算法被固定(增量 sum 是),你会看到当sum == size-1 最后一个数字有一个9/10随机选择的概率,即平均 10 次循环来获得该数字。 proba 会随着之前的数字而减少 - 但如果你不走运,最后会找到 4 个相同的数字!或平均 40 次循环...没有进行计算,但应该接近 O(n²)
  • 如果出现的范围和次数是固定的,并且您生成了整个数字列表,这种方法与将所有数字放在一个列表中然后打乱列表的结果相同,但是效率极低.请参阅 giorashc(包括 cmets)的答案,以获得具有相同结果的更好解决方案。
【解决方案4】:

您可以创建一个方法来检查生成的数字在数组中是否存在超过 4 次,如果存在则创建一个新的随机数。它应该是这样的:

import java.util.Random;

public class rndNumberGenerator {

    public static void main (String[] args) {

        int[][] myArray = new int[2][5];
        Random rand = new Random();
        int randomNumber;

        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 5; j++) {

                do {
                    randomNumber = rand.nextInt(11);
                } while(overMax(myArray, randomNumber) == true);

                myArray[i][j] = randomNumber;

                System.out.print(" " + myArray[i][j]);

            }
        }

    }

    public static boolean overMax(int[][] array, int number) {

        int max = 4;
        int count = 0;

        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 5; j++) {

                if (array[i][j] == number) {
                    count++;
                }

            }
        }

        if (count >= max)
            return true;
        else
            return false;

    }
}

希望对您有所帮助,如果您有任何其他问题,请随时提出。

【讨论】:

    【解决方案5】:

    我接受 pshemek 的建议(投赞成票):我使用 ArrayList 而不是 Set,因为它不能包含重复的数字,而且您不必进行控制。

    一个实现:copy{right, left} 属于 pshemek,我只是扩展了这个想法:)

    public class Example {
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            int[] numbers = new int[11];
            int sum = 0;
            final int range = 10;
            final int noOfOccurances = 4;
            Arrays.fill(numbers, 0);
            Random generator = new Random();
            Set<Integer> numbersArray = new TreeSet<Integer>();
            while (sum != range * noOfOccurances) {
                int randomNumber = generator.nextInt(range) + 1;
                sum++;//correction for first comment
                numbersArray.add(randomNumber); // randomNumber will never be twice: a Set cointains ever one and only one instance of an determinated element
            }
            System.out.println(numbersArray);
        }
    
      }//end class
    

    【讨论】:

    • 你在哪里增加总和。
    【解决方案6】:

    你可以自己写:

    public static class CountedRandom {
        // My rng.
        Random rand = new Random();
        // Keeps track of the counts so far.
        Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
        // The limit I must apply.
        final int limit;
    
        public CountedRandom(int limit) {
            this.limit = limit;
        }
    
        public int nextInt(int l) {
            int r;
            do {
                // Keep getting a new number until we hit one that has'n been overused.
                r = rand.nextInt(l);
            } while (count(r) >= limit);
            return r;
        }
    
        private int count(int r) {
            // How many times have we seen this one so far.
            Integer counted = counts.get(r);
            if ( counted == null ) {
                // Never!
                counted = new Integer(0);
            }
            // Remember the new value.
            counts.put(r, counted + 1);
            // Returns 0 first time around.
            return counted;
        }
    }
    
    public void test() {
        CountedRandom cr = new CountedRandom(4);
        for ( int i = 0; i < 50; i++ ) {
            System.out.print(cr.nextInt(4)+",");
        }
        System.out.println();
    }
    

    请注意,如果您要求的数字太小,这个会挂起(就像我在测试中所做的那样)。

    打印

    2,0,1,2,1,1,3,3,0,3,0,2,2,0,1,3,
    

    然后挂起。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-28
      • 2023-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-22
      • 1970-01-01
      • 2016-01-30
      相关资源
      最近更新 更多