如何解决;“生日悖论”;在java中不使用嵌套循环?

如何解决;“生日悖论”;在java中不使用嵌套循环?,java,android-studio,Java,Android Studio,我曾经尝试过嵌套循环的问题,但是如果不使用嵌套循环并且在同一个类文件中,如何解决它呢。问题是找出两个人在一个群体中拥有相同生日的概率。它应该产生以下输出:在一组5人和10000个模拟中,概率为2.71%。注意:使用arraylist或hashmap是可能的。但我不知道怎么做。多谢各位 public void process() { int groupSize = System.out.getSize(); int simulationCount = System.out.getC

我曾经尝试过嵌套循环的问题,但是如果不使用嵌套循环并且在同一个类文件中,如何解决它呢。问题是找出两个人在一个群体中拥有相同生日的概率。它应该产生以下输出:在一组5人和10000个模拟中,概率为2.71%。注意:使用arraylist或hashmap是可能的。但我不知道怎么做。多谢各位

public void process() {
    int groupSize = System.out.getSize();
    int simulationCount = System.out.getCount();

    if (groupSize < 2 || groupSize > 365) {
        System.out.makeAlertToast("Group Size must be in the range 2-365.");
        return;
    }
    if (simulationCount <= 0) {
        System.out.makeAlertToast("Simulation Count must be positive.");
        return;
    }

    double percent = calculate(groupSize, simulationCount);

    // report results
    System.out.println("For a group of " + groupSize + " people, the     percentage");
    System.out.println("of times that two people share the same birthday        is");
    System.out.println(String.format("%.2f%% of the time.", percent));

}


public double calculate(int size, int count) {
    int numTrialSuccesses = 0;

    // Repeat and count.
    for (int n=0; n < count; n++) {
        Random rand = new Random(n);
        // Generate birthdays (random array)
        int[] birthdays = new int [size];
        for (int i=0; i <size; i++) {
            birthdays[i] = rand.nextInt (365);
        }

        // Check if any two match.
        boolean matchExists = false;
        for (int i=0; i < size; i++) {
            for (int j=0; j < size; j++) {
                if ( (i != j) && (birthdays[i] == birthdays[j]) ) {
                    // Note: musn't forget the i!=j test above!
                    matchExists = true;
                    if (matchExists) break;
                }
            }
        }

        if (matchExists) {
            numTrialSuccesses ++;
        }

    } //end-for-trials

    double prob = ((double) numTrialSuccesses *100)/ (double) count;
    return prob ;

}

}
公共作废流程(){
int groupSize=System.out.getSize();
int simulationCount=System.out.getCount();
if(groupSize<2 | | groupSize>365){
System.out.makeAlertToast(“组大小必须在2-365之间”);
返回;
}
如果(模拟计数此代码:

        int[] birthdays = new int [size];
        for (int i=0; i <size; i++) {
            birthdays[i] = rand.nextInt (365);
        }

        // Check if any two match.
        boolean matchExists = false;
        for (int i=0; i < size; i++) {
            for (int j=0; j < size; j++) {
                if ( (i != j) && (birthdays[i] == birthdays[j]) ) {
                    // Note: musn't forget the i!=j test above!
                    matchExists = true;
                    if (matchExists) break;
                }
            }
        }

        if (matchExists) {
            numTrialSuccesses ++;
        }
int[]生日=新int[size];

对于(int i=0;i一种使用奇特数据结构的解决方案
HashSet
。如评论中所述,您可以使用365个元素的布尔数组,如果遇到该数组,可以将其切换为true

下面是一个类似的想法。如果集合中还不包含生日,则将每个生日添加到集合中。如果集合中确实包含生日,则增加计数器。现在,您不需要麻烦的第二次迭代,因此您的时间复杂度将降到O(n)。由于集合中的查找具有恒定的时间,因此它将降到O(n)

public double calculate(int size, int count) {
    int numTrialSuccesses = 0;

    // Repeat and count.
    for (int n=0; n < count; n++) {
     Random rand = new Random(n);

     Set<Integer> set = new HashSet<Integer>();
        for (int i=0; i <size; i++) {
            int bday = rand.nextInt (365);
            Integer bday1 = new Integer(bday);
            if(set.contains(bday1)){
               numTrialSuccesses++;
               break;
             }else{
                 set.add(bday1);
             }
        }
    } //end-for-trials

    double prob = ((double) numTrialSuccesses *100)/ (double) count;
    //like wise comments have noted this is not the probability!!! Just a simulation
    return prob ;

}
public双重计算(整数大小,整数计数){
int numtrialsuccess=0;
//重复数数。
对于(int n=0;n
double calculateProbability(int trials, int people) {

    //for trials = 10_000, people = 5
    int timesWithSharedBirthday =  IntStream.range(0,trials)     // Run 10_000 trials
                                            // generate 5 bdays, count distinct ones. Filter out those with 5 distinct
                                            .filter(i -> ThreadLocalRandom.current().ints(people,1,365).distinct().count() != people) 
                                            .count();          // Add up the runs without five distinct bdays.

    return probability = 100.0 * timesWithSharedBirthday / trials;
}

我不知道你的在线分级机会怎么样,但是用流练习是很有趣的。

没有任何必要用固定数量的生日来超越原语

创建一个包含365个存储桶的数组,并在每个存储桶中记下生日的日期。这样可以使用高效的数组操作

下面的代码不是每次都创建一个新数组,而是使用
System.arraycopy
在现有数组上复制一个调零后的数组,这样可以获得一些性能

尽管如此,与前面给出的
HashSet
示例相比,性能增益充其量是适中的,性能提高了5到6倍,但并没有提高几个数量级。 因此,如果使用
HashSet
和类似的工具可以提高清晰度,那么就要提高清晰度

  public double calculate(int size, int count) {
    int numTrialSuccesses = 0;
    int[] daysOfYear = new int[365];
    final int[] empty = new int[365];
    // Repeat and count.
    for (int n = 0; n < count; n++) {
      Random rand = new Random(n);

      // Efficiently clear out the array
      System.arraycopy(empty, 0, daysOfYear, 0, 365);

      boolean matchExists = false;
      for (int i = 0; i < size; i++) {
        int birthday = rand.nextInt(365);
        // Compare, then increment, the bucket for the birthday
        if(daysOfYear[birthday]++>0){
          matchExists = true;
          break;
        }
      }
      if (matchExists) {
        numTrialSuccesses++;
      }
    } //end-for-trials

    double prob = ((double) numTrialSuccesses * 100) / (double) count;
    return prob;
  }
public双重计算(整数大小,整数计数){
int numtrialsuccess=0;
int[]daysOfYear=新int[365];
最终整数[]空=新整数[365];
//重复数数。
对于(int n=0;n0天){
matchExists=true;
打破
}
}
如果(匹配存在){
numtrialsuccess++;
}
}//审判结束
双概率=((双)numTrialSuccesses*100)/(双)计数;
返回问题;
}

你遇到了什么问题?你目前的方法是模拟这些概率。你知道你可以简单地计算它们吗?给定一组人的数量,你只需做一些数学运算,就可以得到匹配生日的确切概率。只需使用
bool[365]
数组和索引按
第1天
@GhostCat对我来说这听起来像是一个家庭作业问题:类似于“通过模拟小组经验验证生日悖论的数学分析。”这可能会有帮助。没有解释…没有更新投票。好的答案不仅仅是工作代码!我要发布的是,但是ArrayList.contains是O(n),所以这实际上并没有改变双循环:说“把这个改成那个”…不是一种解释。尤其是当您的代码最终执行相同的操作时。您知道,List.contains()与Set.contains()不是“相同”的。您只是将该内部循环放在某个方法调用中…但隐藏某些内容并不等于消除它。问题是:“如何在不使用嵌套循环的情况下解决它?”在那之后,他提到他在谈论数组列表或散列,然后,你可以推断他指的是寻找重复的代码,答案是正确的,即使你想让StackOverflow中的第一个商业广告真正要问的问题变得更复杂…@RicardoOrtegaMagañI使用了上述代码,但autograder仍然超时。但就我看来,解决方案是完全正确的(2.71%)当我在eclipse和BlueJ中运行它时,我不知道autograder有什么问题。我试过运行这段代码,但值与实际答案相差不大。对于5个人和10000个模拟,我得到的概率是2.73%,但应该正好是2.71%。我编辑过,一旦遇到匹配,就从组中分离出来……听起来可能是这样问题。如果分子是至少有一个匹配的总组,分母是总组,那么上面的代码现在应该可以工作了。完美的解决方案。
  public double calculate(int size, int count) {
    int numTrialSuccesses = 0;
    int[] daysOfYear = new int[365];
    final int[] empty = new int[365];
    // Repeat and count.
    for (int n = 0; n < count; n++) {
      Random rand = new Random(n);

      // Efficiently clear out the array
      System.arraycopy(empty, 0, daysOfYear, 0, 365);

      boolean matchExists = false;
      for (int i = 0; i < size; i++) {
        int birthday = rand.nextInt(365);
        // Compare, then increment, the bucket for the birthday
        if(daysOfYear[birthday]++>0){
          matchExists = true;
          break;
        }
      }
      if (matchExists) {
        numTrialSuccesses++;
      }
    } //end-for-trials

    double prob = ((double) numTrialSuccesses * 100) / (double) count;
    return prob;
  }