【问题标题】:Generate Distinct Combinations PHP [closed]生成不同的组合PHP [关闭]
【发布时间】:2012-02-04 02:19:56
【问题描述】:

我需要一种有效的算法来生成不同的组合(不允许重复)。每个组合有 5 个不同的数字(不同的数字),范围在 1 到 99 之间。结果必须存储在数组中。如果可能的话,我希望允许自定义的数字和范围。数字顺序无所谓(01 02 03 = 03 01 02)

 Ex.: 
 01 02 03 04 05
 02 03 04 05 06
 ...

有人可以帮我建造它吗?我想从数组中挑选一些随机组合。现在我正在使用 mt_rand 生成随机组合,但这需要太多时间,太慢了!我相信碰巧经常重复然后需要时间来生成新的和新的......

【问题讨论】:

  • 搜索fisher-yates shuffle。
  • 您知道您需要多少内存来执行此操作吗? 199 中的 5 有 71,523,144 种独特组合。为什么您实际上需要知道所有可能的组合?几乎可以肯定有一个更好的替代方案来解决它们......也许只是根据需要生成尽可能多的洗牌唯一性,这肯定比 71,523,144 少得多。
  • How to reduce for loop speed 的可能重复项
  • @Mark Ba​​ker,感谢您的评论!好吧,我考虑过生成小块,然后提取我想要的组合。现在我使用带有 rand 函数的循环它似乎经常重复数字然后我不得不再次运行循环,试图再次获得一个不同的组合,当组合增加时它变得如此缓慢。
  • 您可以在here 中执行类似操作,但删除字符数较高的那些 1。然后将 char 转换为它的代表数字(或使用数字范围的数组而不是字符集并稍后在输出数组(而不是字符串)上使用值计数)。

标签: php algorithm brute-force


【解决方案1】:

我很快把这个放在一起,似乎有效。

<?php

$range_low = 1;
$range_hi  = 99;
$num_sets  = 10;

$set = generateSet($range_low, $range_hi, $num_sets);

print_set($set);

function generateSet($range_low, $range_hi, $numSets = 5, $numPerSet = 5)
{
    $return  = array();
    $numbers = array();

    for($i = $range_low; $i <= $range_hi; ++$i) {
        $numbers[] = $i;
    }

    for ($s = 0; $s < $numSets; ++$s) {
        $set = array_values($numbers);
        shuffle($set);

        $return[$s] = array();

        for ($i = 0; $i < $numPerSet; ++$i) {
            $val = array_shift($set);
            $return[$s][] = $val; 
        }
    }

    return $return;
}

function print_set($set)
{
    foreach($set as $subset) {
        foreach($subset as $value) {
            echo str_pad($value, 2, '0', STR_PAD_LEFT) . ' ';
        }
        echo "\n";
    }
}

样本输出:

90 75 89 43 57 
24 54 38 35 10 
77 21 55 33 83 
37 15 61 09 44 
25 31 85 17 20 
48 37 45 13 20 
82 70 74 64 72 
07 24 33 64 45 
34 13 39 33 05 
13 77 87 70 64 

要 Fisher-Yates 对数组进行洗牌,请参阅 this comment on shuffle 了解可以用来代替洗牌的函数。

希望对您有所帮助。

【讨论】:

  • 问题中所述的组合不允许重复。在 1-99 的情况下,它们很少重复,但如果你选择 1-10 之类的东西,那么你的代码会产生很多重复
  • 它将值从数组中移出,因此它不能在同一个集合中重复,因为该值已从数组中删除并且无法再次选择。
  • 我并不是说一组中的相同数字。我是说它会产生相同的集合。
【解决方案2】:

如果你真的需要一整套所有可能的组合:

function combinations($set,$length) { 
  $combinations = array(); 

  $setCount = count($set);  
  for($i = 0, $n = $setCount; $i <= ($n - $length); $i++) { 
    $combination = array(); 
    $combination[] = $set[$i]; 

    if($length > 1) { 
      $combination = array_merge( 
        $combination, 
        combinations(array_slice($set,1+$i), $length-1) 
      ); 
    } 

    $combinations[] = $combination; 
  } 

  return $combinations; 
} 

$allYourNumbers = range(1,99);
$allCombinations = combinations($allYourNumbers, 5);

然后您可以随机播放 $allCombinations 并提取任意数量的内容,但您需要大量内存和大量时间...这样做永远不会高效

【讨论】:

    【解决方案3】:

    这是一个简单的代码,应该运行得相当快并且按照你的描述去做。

    $numbers = range(1, 99); // numbers to pick from
    $length = 5; // amount of items in the set
    $sets_amount = 15; // amount of sets you want to generate
    shuffle($numbers); // randomize
    
    function get_set($length, &$numbers) {
        return array_splice($numbers, 0, $length);
    }
    
    for ($i = 0; $i < $sets_amount; $i++)
        print_r(get_set($length, $numbers));
    

    注意:它仅在您需要几种组合时才有效。你没有说你想要所有可能的,所以我想如果你只需要一堆 - 这是非常快速和简单的方法。

    如果要慢一点(生成的越多 - 速度越慢),但生成 任何 数量的集合,您可以使用此代码。

    $numbers = range(1, 99); // numbers to pick from
    $length = 5; // amount of items in the set
    $sets_amount = 200; // amount of sets you want to generate
    $existing = array(); // where we store existing sets
    $shuffle_period = count($numbers) - $length - 1; // how often we re-randomize the elements
    $j = 0;
    
    for ($i = 0; $i < $sets_amount; $i++, $j++) {
        if (!($i % $shuffle_period)) {
            shuffle($numbers); // randomize at first go and on $shuffle_period
            $j = 0;
        }
        do {
            $arr = array_slice($numbers, $j, $length);
        } while (in_array($arr, $existing));
        $existing[] = $arr;
    }
    
    print_r($existing);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      • 2014-06-29
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 2012-11-06
      • 1970-01-01
      相关资源
      最近更新 更多