【问题标题】:get 4 random numbers得到4个随机数
【发布时间】:2014-06-28 20:07:51
【问题描述】:

我需要生成 4 个具有给定范围的不同随机数。像这样:

define('min', 3000);
define('range', 6000);
define('diff', 200);

$array[0] = rand(min ,min + range);
$array[1] = rand(min ,min + range);
while(abs($array[0]-$array[1])<diff)
    $array[0] = rand(min ,min + range);
$array[2] = rand(min ,min + range);
while((abs($array[2]-$array[0])<diff)
    ||(abs($array[2]-$array[1])<diff))
    $array[2] = rand(min ,min + range);
$array[3] =rand(min ,min + range);
while((abs($array[3]-$array[0])<diff)
    ||(abs($array[3]-$array[1])<diff)
    ||(abs($array[3]-$array[2])<diff))
    $array[3] = rand(min ,min + range);

有没有办法优化这个算法?

【问题讨论】:

  • 为什么要写这么多代码?
  • 这就像“准备好 4 具棺材”吗?
  • 你能简单描述一下吗?真正的意义是什么?
  • 如果你只需要生成数字,rand(min ,min + range);四次就够了,但是你添加了很多条件,那么你能解释一下'为什么'吗?
  • 差异是两个随机数之间的最小差异吗?还是只是一个固定的差异?

标签: php algorithm random


【解决方案1】:

首先,您可能想要声明您希望四个随机数在同一间隔内但彼此之间的距离最小(如代码所示)。您当前的方法涉及循环,可能是无限期的,但可能只是一段时间,直到达到这些数字。

只要你只需要四个随机数,你这样做就没有多大关系。它可以写得更通用,允许绘制多于四个的数字的自然扩展,但这并不一定会使其更快,即使是四个数字。

假设您想要花费时间的上限(您当前的代码仅以某种概率给出),这里有一个可行的算法(只要间隔足够大):绘制一个随机数 N 并创建区间的两个分区,一个用于小于 N 的有效后续数字,另一个用于大于 N 的有效后续数字。对于每个后续的随机数,随机选择一个可用的分区并以相同的方式继续。

如果您忽略 count($intervals) 所花费的时间,这将在 O($n) 中运行(它可能需要 O(1),但它会变得有点丑陋)。我不能说这个算法产生的数字与你的初始算法具有相同的概率分布。一件事表明概率分布是有偏差的:一个分区是随机选择的,权重相等,而不是基于区间有多大。

<?php

function random_interval($n, $min, $max, $distance) {
    $result = array();
    $intervals = array(array($min, $max));
    while ($n-- > 0 && count($intervals) > 0) {
        // find a random, valid interval
        $i = array_rand($intervals);

        // extract this interval
        $cur_min = $intervals[$i][0];
        $cur_max = $intervals[$i][1];
        unset($intervals[$i]);

        // find a random value within this interval
        $r = rand($cur_min, $cur_max);
        $result[] = $r;

        // if there are valid intervals before and after $r,
        // add these intervals back to the set of intervals
        if ($r - $distance > $cur_min)
            $intervals[] = array($cur_min, $r - $distance);
        if ($r + $distance < $cur_max)
            $intervals[] = array($r + $distance, $cur_max);
    }
    return $result;
}

【讨论】:

    【解决方案2】:

    生成第n个数时,在(min, min+range-2*diff*(n-1))范围内生成,然后遍历前面的数,如果当前生成的数被“阻塞”通过前一个数字,将 2*diff 添加到它。这是执行此操作的代码,但也考虑了先前生成的数字接近边界的情况(在这种情况下,您不需要将 2*diff 添加到新生成的数字,只需较小的数量):

    define('min', 3000);
    define('range', 6000);
    define('diff', 200);
    
    $numbers = array();
    $bounds = array();
    
    for($i = 0; $i<4; $i++){
        $min = min;
        $range = range;
        foreach($bounds as $amount){
            $range -= $amount;
        }
        $rnd = rand($min, $min + $range);
        foreach($bounds as $position => $amount){
            if($position <= $rnd){
                $rnd += $amount;
            }
            else{
                break;
            }
        }
        $numbers[$i] = $rnd;
        if($rnd <= min + diff){
            $bounds['0'] = $rnd - min + diff; 
        }
        elseif($rnd >= min + range - diff){
            $bounds[strval($rnd-diff)] = min + range - $rnd + diff;
        }
        else{
            $bounds[strval($rnd-diff)] = 2 * diff;
        }
        ksort($bounds);
    }
    print_r($numbers);
    

    它没有优化,它运行在 O(n^2log(n)) 中,甚至认为 O(nlog(n)) 也是可能的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      • 2020-06-29
      • 2014-05-14
      • 2011-02-08
      • 2015-09-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多