生成随机序列时的尴尬标准

时间:2011-06-28 01:43:09

标签: php random numbers sequence

在给定范围内生成符合我具体标准的非重复整数序列需要做些什么?

以下是标准:

  1. 仅使用介于1和MAX之间的数字(假设为9)。
  2. 数字不能在序列中重复,除了:
    2A。必须重复序列中前5个数字中的两个。
    2B。这两个数字必须在最后一个序列中最后5个位置的随机点重复(最后5个包括重复)。
  3. 例如: SET: 1,2,3,4,5,6,7,8,9

    随机序列(带重复):
         2,4,6,9,3,1,5,2,8,7,3
         r, , , ,r, , ,x, , ,x

    这里我已经指出了随机选择的数字(随机序列中的前5个)和r以及它们随机放置的插入点(进入最后5个)最终序列)x

    非常感谢任何帮助解决这个问题。实际使用会比这更复杂,但我知道一旦我能做到这一点我将需要做什么。

    修改

    为了澄清一点,我有1-20,我需要一个22位的随机序列。必须使用每个号码,两个将使用我原来的帖子中讨论的两次。我选择了10以上简化了一点。我应该能够适应你所有的逻辑。

6 个答案:

答案 0 :(得分:0)

我假设当你说"非重复"你是说" distinct" (独特的)而不是"最终成为周期性的#34; (如" pi的数字不重复")

  1. 在您的范围内生成 n 不同的整数。
  2. 从第一个中选择两个5.将这些 a b 称为。
  3. 从列表中删除最后3个。
  4. 在子列表中的位置0,1,2或3处插入 a
  5. 在子列表中的位置0,1,2,3或4处插入 b
  6. 将子列表添加回列表末尾。
  7. 不需要删除子列表,但可以更容易地进行概念化。

    如果n + 2小于10,该怎么做并不明显。特别是,该算法可能会因n< 5并返回错误的结果n = 7。

答案 1 :(得分:0)

要在范围内生成不同的数字,您可以使用以下内容:

$arr_num = array();

while(count($arr_num)<=7)
{
  $num = rand(1, 9);
  if (!in_array($num, $arr_num))
  {
    $arr_num[] = $num;
  }
}

$ arr_num现在有8个不同的元素。选择数组的五个元素:

for ($i=0; $i<=4; $i+=1)
{
  $new_arr[$i] = $arr_num[$i];
}

现在从$ new_arr数字中选择两个数字:

$r1 = array_rand($new_arr);
$r2 = array_rand($new_arr);

现在,您可以在最后一个随机位置的两个位置将这些数字插入原始数组中。希望它有所帮助!

答案 2 :(得分:0)

如果我理解正确,你有1到N个随机数,必须在10组排列中使用,并且有一些关于重复的特定标准。在PHP中,我建议这(不计算php-internals)O(n)解决方案:

//Generate a full list of keys
$source = range(1, MAX);
//NOTE: if MAX < 10, you must pad the array

//Get a random group of 10 of the keys
$input = array_rand(array_flip($source), 10);

//Shuffle (can be done later as well; this is the randomization).
//array_rand() does not change order.
shuffle($input);

//Select the first of 5 that must be repeated in the last 5
$one = rand(0, 4);
$onev = $input[$one];

//Remove this array key to prevent collisions with the second of 5
$input = array_diff($input, array($onev));

//Select a random index in the last 5 to be replaced with $one
$rep = rand(5, 9);
$repv = $input[$rep];

//Remove this array key to prevent collisions with the other to-be-replaced
$input = array_diff($input, array($repv));

//Acquire the new keys list of input now that two elements have been removed
$keys = array_slice(array_keys($input), 0, 3);
//Select the second-of-5 to replace in the last 5.  No worry of collision now.
$two = array_rand($keys, 1);
$two = $keys[$two];

//Select the second from the last-of-5 to be replaced by $two
//No worry of collision because the other index is removed.
$keys = array_slice(array_keys($input), 4, 8);
$rept = array_rand($keys, 1);
$rept = $keys[$rept];

//Replace one of the last-of-five with one of the first-of-five
$input[$rept] = $input[$two];

//Restore removed keys as well as perform replacement of other last-of-five
$input[$one] = $onev;
$input[$rep] = $onev;

//re-randomize based on shuffle
ksort($input);

没有循环,没有条件。

答案 3 :(得分:0)

$max = 15;

$array = array(1, $max);
for($x = 1; $x <= $max; $x++)
{ $array[$x] = rand(1, $max); }

$firstDup = $array[rand(1,5)];
$secondDup = $firstDup;
do { $firstDup = $array[rand(1,5)];
} while($firstDup == $secondDup);

do { $array[rand($max-5,$max)] = $firstDup;
} while(!in_array($firstDup,array_slice($array,$max-5,5)));

do { $array[rand($max-5,$max)] = $secondDup;
} while(!in_array($secondDup,array_slice($array,$max-5,5)));

答案 4 :(得分:0)

希望这能让你顺利开始:

$max = 20;    // max value
$repeats = 2; // numbers to be repeated

$nums = range(1, $max);
shuffle($nums);

$halfPoint = ceil($max / 2);
$firstHalf = array_slice($nums, 0, $halfPoint);

$repeaters = array_intersect_key($firstHalf, array_flip(array_rand($firstHalf, $repeats)));
$secondHalf = array_merge(array_slice($nums, $halfPoint), $repeaters);
shuffle($secondHalf);

$result = array_merge($firstHalf, $secondHalf);

var_dump(join(',', $result));

答案 5 :(得分:0)

对此解决方案发出警告。我不会将它用于大量数字。如果我为更大的集合做同样的解决方案,我会使用array_splice从数组中删除选定的成员。当您获得更大的空间时,在您的范围内找到未使用的数字会变得非常昂贵,并且需要比下面的强力方法更好的解决方案。

这将构建目标集的一半。你会打两次,每半个一次。

function build_half($min, $max, $num_elements, $arr = array() ){

  while( count($arr) <= $num_elements)
   {
      $candidate = rand($min, $max);
      if( !in_array($candidate, $arr))
        {
          array_push($arr, $candidate);
        }
    }
   return $arr;
}

这将从数组中获取$ this_many元素。

function random_grab($arr, $this_many){      // don't try this on the subway
  $nums_to_repeat = array();

  // catch some edge cases...
  if( $this_many > count($arr) )
    {
      return FALSE;
    }
  else if( $this_many == count($arr) )
    {
      return shuffle($arr);
    }

  while( count($nums_to_repeat) <= $this_many) 
    {
      $rand_key = rand(0, count($arr) - 1);

      if( ! in_array($arr[$rand_key], $nums_to_repeat))
        {
          array_push($nums_to_repeat, $arr[$rand_key]);
        }
    }
 return $nums_to_repeat;
}

这是一个相当专业的案例,但可以通过允许偏移楼层和天花板作为参数传递而更加通用。对于你的问题,他们将是5和9,所以我们直接派生他们。

function random_insert_2nd_half($target, $source){
  $offsets_consumed = array();
  $num_elements = count($target);

  while( count($source) > 0 )
    {
      $offset = rand( ($num_elements/2), $num_elements - 1);

      if( ! in_array( $offset, $offsets_consumed)
        {
          $arr[$offset] = array_pop($nums_to_repeat);
        }
    }
}

好的,完成所有这些之后,让我们把它付诸实践。

// Generate the first half of the array
$my_array = $repeated_nums = array();
$my_array = build_half(1, 10, 5);

// then grab the 2 random numbers from that first half.
$repeated_nums = random_grab($my_array, 2);

// So now we have our random numbers and can build the 2nd half of the array.
// we'll just repeat the call to the first function.
$my_array = build_half(1, 10, 5, $my_array);

// Then swap out two of the values in the second half.
$my_array = random_insert_2nd_half($my_array, $repeated_nums);

// at this point $my_array should match what you are looking for.