将'n`双倍均匀地除以总和`s`,其中每个双重低于1(具有适当的性能)

时间:2018-05-18 20:03:09

标签: java performance random range uniform-distribution

我目前正致力于this (code-golf) challenge,而且我很难将整数金额n和总十进制数{{}的四项要求结合起来。 1}}(根据我们应该支持的范围:s1 <= n <= 10):

  1. 0 <= s <= n项应该是随机的,并且均匀划分
  2. 所有项目的总和必须等于n
  3. 所有项目均不得超过1.0
  4. 无论s
  5. ,代码必须在1秒内为每n <= 10次运行

    基于this Stackoverflow answer我知道如何统一划分给定范围内的项目。例如,使用s,我可以在n=5, s=4.5范围内创建一个n-1 = 4项列表,其中包含额外的前导[0, 1.5]和尾随0。然后我可以计算所有差异(因此所有差异的总和将等于1.5)。这里有一个可能的实现:

    s=4.5

    示例输出:

    int n=5; double s=4.5;
    
    double[] randomValues = new double[n+1];
    randomValues[n] = s;
    for(int i=1; i<n; i++)
      randomValues[i] = Math.random()*s;
    java.util.Arrays.sort(randomValues);
    System.out.println("Random values:\n"+java.util.Arrays.toString(randomValues)+"\n");
    
    double[] result = new double[n];
    for(int i=0; i<n; i++)
      result[i] = Math.abs(randomValues[i]-randomValues[i+1]);
    System.out.println("Result values:\n"+java.util.Arrays.toString(result)+"\n");
    
    double resultSum = java.util.Arrays.stream(result).sum();
    System.out.println("Sum: "+resultSum);
    System.out.println("Is the result sum correct? "+(s==resultSum?"yes":"no"));
    

    Try it online.

    以上内容符合上述四项要求中的三项要求(1,2和4)。但是,不是3。

    我可以在它周围缠绕一个循环,只要Random values: [0.0, 1.3019797415889383, 1.9575834386978177, 2.0417721898726313, 4.109698885802333, 4.5] Result values: [1.3019797415889383, 0.6556036971088794, 0.08418875117481361, 2.0679266959297014, 0.39030111419766733] Sum: 4.5 Is the result sum correct? yes - 数组中的一个项目仍然大于1,它就会继续循环:

    result

    对于大多数for(boolean flag=true; flag; ){ ... // Same code as above flag=false; for(double d:result) if(d>1) flag=true; } n,这仍然相对较快: Try it online(删除/移动打印件不会溢出控制台)

    但是,最后四个s - 禁用的测试用例,预期随机值的平均值接近//,时间过长(甚至在TIO上60秒后超时)

    所以这就是我的问题所在。 如何按照我的方式统一划分值,并记住每个值1的范围,并且表现良好?在顶部的链接代码 - 高尔夫挑战中我看看其他编程语言中的一些工作示例,比如Python或JavaScript,但是从一种编程语言移植到另一种编程语言需要更长时间的代码高尔夫挑战通常并不是非常简单。

1 个答案:

答案 0 :(得分:0)

好的,找到了一个基于已经给出的JavaScript答案的解决方案。如果s*s>n我将s更改为n-s并在结果数组中设置标记以使用1-diff而不是diff

所以它总是变成:

boolean inversedFlag = 2*s>n;
double S = s;
if(inversedFlag)
  S = n-S;

double[] result = new double[n];

for(boolean flag=true; flag; ){
  double[] randomValues = new double[n+1];
  randomValues[n] = S;
  for(int i=1; i<n; i++)
    randomValues[i] = Math.random()*S;
  java.util.Arrays.sort(randomValues);

  for(int i=0; i<n; i++){
    double diff = Math.abs(randomValues[i]-randomValues[i+1]);
    result[i] = inversedFlag ? 1-diff : diff;
  }

  flag=false;
  for(double d:result)
    flag |= d>1;
}

System.out.println("Result values:\n"+java.util.Arrays.toString(result)+"\n");

double resultSum = java.util.Arrays.stream(result).sum();
System.out.println("Sum: "+resultSum );
System.out.println("Is the result sum correct? "+(s==resultSum?"yes":"no"));

System.out.println();
System.out.println("--------------------------------------------------");
System.out.println();

Try it online.

现在我只需再次打高尔夫球,但这与Stackoverflow问题无关。 :)