代码之家  ›  专栏  ›  技术社区  ›  defines

在PHP中生成任意长度的有序(加权)组合

  •  4
  • defines  · 技术社区  · 16 年前

    aa
    ab
    ba
    bb
    ac
    bc
    ca
    cb
    cc
    

    以下是长度3的正确列表:

    aaa
    aab
    aba
    abb
    baa
    bab
    bba
    bbb
    aac
    abc
    bac
    bbc
    aca
    acb
    bca
    bcb
    acc
    bcc
    caa
    cab
    cba
    cbb
    cac
    cbc
    cca
    ccb
    ccc
    

    对于任意数量的元素,这很容易实现2个或3个单词(设置长度)的组合,但是可以对任意长度执行此操作吗?我想用PHP实现这一点,但如果是伪代码,甚至是算法的摘要,将不胜感激!

    4 回复  |  直到 16 年前
        1
  •  1
  •   Erika    16 年前

    这里有一个递归函数,可能正是您需要的。我们的想法是,当给定一个长度和一个字母时,首先生成短一个字母但不包含该字母的所有序列。把新字母加到末尾,你就得到了这个字母序列的第一部分。然后向左移动新字母。循环阅读每个字母序列 右边那个新的。

    如果你有gen(5,d)

    (aaaa)d
    (aaab)d
    ...
    (cccc)d
    

    当它完成了a-c组合,它就可以了

    (aaa)d(a)
    ...
    (aaa)d(d)
    (aab)d(d)
    ... 
    (ccc)d(d)
    

    当它把d作为第四个字母时,它会移到第三个字母

    (aa)d(aa)
    

    <?php 
    /** 
     * Word Combinations (version c) 6/22/2009 1:20:14 PM 
     * 
     * Based on pseudocode in answer provided by Erika: 
     *   http://stackoverflow.com/questions/1024471/generating-ordered-weighted-combinations-of-arbitrary-length-in-php/1028356#1028356 
     *   (direct link to Erika's answer) 
     * 
     * To see the results of this script, run it: 
     *   http://stage.dustinfineout.com/stackoverflow/20090622/word_combinations_c.php 
    **/ 
    
    init_generator(); 
    
    function init_generator() { 
        global $words; 
        $words = array('a','b','c'); 
        generate_all(5);
    
    
    } 
    
    function generate_all($len){
        global $words;
        for($i = 0; $i < count($words); $i++){
            $res = generate($len, $i); 
    
            echo join("<br />", $res);  
            echo("<br/>");
        }   
    }
    
    function generate($len, $max_index = -1){ 
        global $words; 
    
        // WHEN max_index IS NEGATIVE, STARTING POSITION 
        if ($max_index < 0) { 
            $max_index = count($words) - 1; 
        } 
    
        $list = array(); 
    
    
        if ($len <= 0) { 
            $list[] = "";
            return $list; 
        } 
    
        if ($len == 1) { 
    
            if ($max_index >= 1) { 
                $add = generate(1, ($max_index - 1));
                foreach ($add as $addit) { 
                    $list[] = $addit; 
                } 
    
    
            } 
            $list[] = $words[$max_index]; 
            return $list; 
        } 
    
        if($max_index == 0) { 
            $list[] = str_repeat($words[$max_index], $len); 
            return $list; 
        } 
    
        for ($i = 1; $i <= $len; $i++){ 
            $prefixes = generate(($len - $i), ($max_index - 1)); 
            $postfixes = generate(($i - 1), $max_index); 
            foreach ($prefixes as $pre){ 
                //print "prefix = $pre<br/>";
                foreach ($postfixes as $post){ 
                    //print "postfix = $post<br/>";
                    $list[] = ($pre . $words[$max_index] . $post); 
                } 
            } 
        } 
        return $list; 
    } 
    
    ?>
    
        2
  •  0
  •   WizKid    16 年前

    我在google上搜索php排列,得到: http://www.php.happycodings.com/Algorithms/code21.html

    我还没有研究代码是好是坏。但它似乎能做你想做的事。

        3
  •  0
  •   chaos    16 年前

    abc
    bac
    bca
    acb
    cab
    cba
    

    也许可以对它进行调整以启用您想要的重复行为。

    varargs mixed array permutations(mixed array list, int num) {
        mixed array out = ({});
        foreach(mixed item : permutations(list[1..], num - 1))
            for(int i = 0, int j = sizeof(item); i <= j; i++)
                out += ({ implode(item[0 .. i - 1] + ({ list[0] }) + item[i..], "") });
        if(num < sizeof(list))
            out += permutations(list[1..], num);
        return out;
    }
    

    FWIW,说明问题的另一种方法是,对于N个元素的输入,您希望在一个以输入元素为节点的完全连通的自连通图中,所有长度为N的路径的集合。

        4
  •  0
  •   Martin Konicek Phil Windley    16 年前

    嵌套循环,其中 是序列的长度(示例中为2和3)。

    可以像这样使用递归:

    :

    generate all sequences of length m:
    {
        start with 0, and generate all sequences of length m-1
        start with 1, and generate all sequences of length m-1
        ...
        start with n, and generate all sequences of length m-1 
    }
    
    generate all sequences of length 0
    {
        // nothing to do
    }
    

    // m is remaining length of sequence, elements is array with numbers so far
    generate(m, elements)
    {
        if (m == 0)
        {
            for j = 0 to elements.length print(words[j]);
        }
        else
        {
            for i = 0 to n - 1
            {
                generate(m-1, elements.push(i));
            }   
        }
    }