【问题标题】:unique permutations of variable length [duplicate]可变长度的唯一排列[重复]
【发布时间】:2014-07-05 01:39:16
【问题描述】:

我需要得到一个任意长度的唯一排列数组:

值数组:a、b、c、d、e、f、g、h、i、j、k、l、m(共 13 个)
预期结果:a、b、c、ab、ac、bc、abc、....
ab == ba(重复)
abc == acb == bca == bac == ...(重复)

到目前为止,我对它进行了蛮力攻击,但对于 13 个元素,这有点乐观。我需要一些更聪明的东西,不幸的是超出了我的数学能力。

我目前的疯狂解决方案:

// Returns the total number of $count-length strings generatable from $letters.
function getPermCount($letters, $count) {
  $result = 1;
  // k characters from a set of n has n!/(n-k)! possible combinations
  for($i = strlen($letters) - $count + 1; $i <= strlen($letters); $i++) {
    $result *= $i;
  }

  return $result;
}

// Decodes $index to a $count-length string from $letters, no repeat chars.
function getPerm($letters, $count, $index) {
  $result = array();
  for($i = 0; $i < $count; $i++) {
    $pos = $index % strlen($letters);
    $result[] = $letters[$pos];
    $index = ($index-$pos)/strlen($letters);
    $letters = substr($letters, 0, $pos) . substr($letters, $pos+1);
  }

  sort($result);    // to be able and remove dupes later
  return implode("", $result);
}

$r = array();
$letters = 'abcdefghijklm';
$len = strlen($letters);
$b = 0;

for ($c = 1; $c <= $len; $c++) {
  $p = getPermCount($letters, $c);
  echo $c." {".$p." perms} - ";
  for($i = 0; $i < $p; $i++) {
    $r[] = getPerm($letters, $c, $i)." ";
    if ($b > 4000000) {
        $r = array_flip($r); // <= faster alternative to array_unique
        $r = array_flip($r); //    flipping values to keys automaticaly removes dupes
        $b = 0;
    } else {
        $b++;
    }
  }

  $r = array_flip($r); // <= faster alternative to array_unique
  $r = array_flip($r); //    flipping values to keys automaticaly removes dupes
  echo count($r)." unique\n";
}

print_r($r);

【问题讨论】:

    标签: php algorithm


    【解决方案1】:

    我试了一下:

    function get_perms(chars) {
        var perms = [ chars[0] ];
        for (var i = 1; i < chars.length; i += 1) {
            len = perms.length;
            for (var j = 0; j < len; j += 1) {
                perms.push(perms[j] + chars[i]);
            }
        }
        return perms;
    }
    
    var chars = [ "a", "b", "c", "d", "e" ], perms = [];
    for (var i = 0; i < chars.length; i += 1) {
        perms = perms.concat(get_perms(chars.slice(i)));
    }
    console.log(perms);
    

    大纲是:

    从全套开始[ "a", "b", "c", "d", "e", .. ]

    生成所有升序排列,aabacabc 等,但从不生成acb。我从["a"] 开始,现在将"b" 添加到所有这些并合并以获得:["a", "ab"],现在将"c" 添加到所有这些并合并:["a", "ab", "ac", "abc"] 等。

    为集合 [ "b", "c", "d", "e", .. ] 再次执行所有这些操作,然后为 [ "c", "d", "e", .. ] 等。

    这应该给你所有没有重复的排列。


    样本输出([ "a", "b", "c", "d", "e" ]):

    ["a", "ab", "ac", "abc", "ad", "abd", "acd", "abcd", "ae", "abe", "ace", "abce", "ade", "abde", "acde", "abcde",
     "b", "bc", "bd", "bcd", "be", "bce", "bde", "bcde",
     "c", "cd", "ce", "cde",
     "d", "de",
     "e"]
    

    在我的机器上生成一整套 13 个字符的时间不到 1 秒,所以我不会费心去测量。另外,我意识到我所做的是 JavaScript 而不是 PHP,转换应该不会太难。

    【讨论】:

    • 这是新的 PHP6 语法? :-)
    • 不,它是 JavaScript :P - 应该很容易转换为 PHP。 array_slicearray_mergearray_pushcount() 而不是 .length
    • 非常感谢 :) 与此同时,我还发现了一种更数学的方法——对于那些感兴趣的人! ...而且这实际上称为组合而不是排列:) mathsisfun.com/combinatorics/combinations-permutations.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 2013-06-23
    相关资源
    最近更新 更多