【问题标题】:Java birthday paradox algorithmJava生日悖论算法
【发布时间】:2016-02-08 10:50:25
【问题描述】:

我对著名的生日悖论做了一个小实现,第一次尝试找到两个随机生日(这里是 1 到 365 之间的整数)之间的冲突。 但它总是返回一个值,比如说 40 和 70,这根本不适合统计数据。 我的算法或随机 int 生成器有问题吗?感谢您的反馈。

代码如下:

public static void main(String[] args){
    int[] birthday = new int[200];

    for(int i = 0; i<20;i++){
        Collision(birthday); 
    }
}

public static int Collision(int birthday[]){
    Random rand = new Random();  
    for(int i = 1; i<birthday.length;i++){        
        birthday[i] = rand.nextInt(365);
    }

    int count = 0;        
    for(int i = 0; i<birthday.length; i++){          
        for(int j= i+1 ; j<birthday.length; j++){            
            if (birthday[i] == birthday[j]){               
                count++;
            }            
        }          
    }

    System.out.print(count+" ");        
    return count;  
}

这是 ex 的输出:

45 50 60 52 53 53 50 49 37 68 52 53 51 43 49 51 46 43 45 35

【问题讨论】:

  • 预期的平均输出是多少?
  • 对于一组 200 人,40 到 70 之间的碰撞计数听起来很合理。
  • 那么你期待什么?碰撞的几率几乎是 100%,你发现平均为 40。这与理论并不矛盾,请参阅birhtday problem calculator
  • 感谢您的回复。根据理论,一组23人的概率是50%,我从来没有过……SP应该在某个地方有一些缺陷。我希望有时 25 或 15 甚至更少......
  • 求和,预期值确实应该略高,在 84 左右。

标签: java algorithm random


【解决方案1】:

编辑:
您在算法中所做的本质上是生成 200 个随机生日并计算它们之间存在的碰撞次数。


你知道你可以通过使用Set 让事情变得更简单,它在开始时是空的。然后在一个简单的 while 循环中生成生日(最多 365 个数字),尝试将它们添加到 Set 中,当你第一次遇到冲突时 - 数字已经在 Set 中 - 你有你的答案(答案是集合的大小)。

也就是说,如果您的目标确实是在最少生日数中找到冲突。

例如,这个:

Random rand = new Random();
for (int t = 0; t < 20; t++)
{
    Set<Integer> b = new HashSet<Integer>();
    while (true)
    {
        int n = rand.nextInt(365);
        if (!b.add(n))
            break;
    }
    System.out.print(b.size() + " ");
}

生产:

15 30 24 4 8 19 10 40 32 31 30 14 41 30 15 7 15 52 24 27

【讨论】:

  • 谢谢,我是 Java 新手,所以我不知道,但我会尝试。
  • 您甚至可以将其简化为if (!b.add(n)) break;
  • @biziclop 啊,很好,我总是忘记Set.add() 返回布尔值:)
  • 更简洁,使用while (b.add(rand.nextInt(365))) ;。不需要临时变量n
  • @pjs 很好,但为了清楚起见,我将保持原样,因为 loukios 说他是 Java 新手。
【解决方案2】:

你的数字看起来相当合理。

但是您反复实例化一个新的Random 实例。这会破坏生成器的统计特性。在程序开始时执行一次。

(最终您也需要考虑 2 月 29 日,但这在很大程度上是二阶效应)。

【讨论】:

    【解决方案3】:

    你的算法看起来不错,结果也合理。

    仅供参考,您可以使用流非常有效地在 1 行中完成所有繁重的工作:

    private static Random rand = new Random(); 
    public static int collision(int size) {
        return size - Stream.generate(() -> rand.nextInt(365)).limit(size).distinct().count();
    }
    

    还有一个 1 行主线:

    public static void main(String[] args){
        Stream.of(200).map(MyClass::collision).forEach(System.out::println);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-28
      • 1970-01-01
      • 2022-06-23
      • 1970-01-01
      • 2020-01-28
      • 1970-01-01
      相关资源
      最近更新 更多