【问题标题】:How can I find all of the permutations consisting of 1 element from a variable number of arrays of variable length?如何从可变数量的可变长度数组中找到由 1 个元素组成的所有排列?
【发布时间】:2010-02-03 02:43:53
【问题描述】:

我有一个数组U 数组D 的长度各不相同。我需要能够返回数组索引的所有排列,这些排列将选择由每个集合中的 1 个元素组成的不同排列。我还要求将此算法表示为只记住最后一个排列的对象,并使用 get_next 方法返回下一个排列。

例如,U = [array_of_size_n1, array_of_size_n2, array_of_size_n3] 会有 n1*n2*n3 排列,每个 3 个元素长。

编辑:套数也不同。

【问题讨论】:

  • 您使用了错误的术语。您所要求的正确术语是笛卡尔积。 en.wikipedia.org/wiki/Cartesian_product
  • @James - “集合的数量也在长度上有所不同”没有意义。 “组数”是一个数字。它没有长度。
  • 谢谢先生。我认为这可能存在一个术语,但如果你只需要继续它所描述的现象,就很难找到它。

标签: algorithm permutation


【解决方案1】:

如果您使用的是 python,这是标准库的一部分:itertools.product。但假设你不是,这里有一个伪代码版本。

// Create an initialised array of indexes.
int[] index0(arrays) {
    // We require all arrays to be non-empty.
    for a in arrays {
        assert len(a) != 0;
    }
    return new int[len(arrays)];
}

// Increment the indices. Returns false when the indices wrap round to the start.
bool next_index(indices, arrays) {
    for (i = len(indices) - 1; i >= 0; --i) {
        indices[i] += 1
        if indices[i] < len(arrays[i]) {
            return true;
        }
        indices[i] = 0;
    }
    return false;
}

您可以像这样使用它(假设您的数组都不是空的)。此示例打印出数组中元素的每个组合。

indices = index0(arrays); 
{
    for (i = 0; i < len(arrays); ++i) {
        print arrays[i][indices[i]];
    }
    print
} while next_index(indices);

【讨论】:

    【解决方案2】:

    您可以在每个数组中为您的个人位置保留一个计数器。在您的 get_next 方法中,将计数器增加 1 并将其修改为数组的长度。然后,每次前一个计数器翻转到 0 时,您只需增加下一个计数器;

    if (pos3 == array_of_size_n3 -1)
    {
       if (pos2 == size_of_array_2 -1)
       {
           pos1 = (pos1 + 1) % size_of_array_1
    
       }
       pos2 = (pos2 + 1) % size_of_array_2
    }
    pos3 = (pos3 + 1) % size_of_array_3
    
    print array1[pos1], array2[pos2], array3[pos3]
    

    编辑:如果数组数量不同,请将位置变量保存在数组中。实际上,无论如何这可能会更好。这样您就可以像引用数组本身一样引用 pos 变量。

    【讨论】:

    • 简洁明了!我的排名比我的好。
    【解决方案3】:

    要了解 Anon 所说的内容,您不能只是遍历它们。您维护类中的状态,以便您知道每个数组的最后一个索引是什么。逻辑是一样的,但你不会在一个连续的循环中运行。伪代码逻辑是:

    get_next() { oldn3 = this.n3; oldn2 = this.n2; oldn1 = this.n1; 如果(this.n3 == this.a3.Count) 这.n3 = 0; 别的 这个.n3++; if(oldn3 > this.n3) 如果(this.n2 == this.a2.Count) 这.n2 = 0; 别的 这个.n2++; if(oldn2 > this.n2) 如果(this.n1 == this.a1.Count) 这.n1 = 0; 别的 这个.n1++; if(oldn1 > this.n1) 返回 NO_MORE_PERMS; 返回[n1,n2,n3]; } 获取当前() { 返回[n1,n2,n3]; }

    【讨论】:

    • 为了使这个适用于任意长度的数组,将你的 n1、n2、n3 等存储在一个数组中。这个数组的索引使得索引 i 是集合 i 的当前元素;另外,请注意您的边界检查。在基于 0 的系统上,我上面的内容不起作用。
    【解决方案4】:

    那么……这直截了当?

    你想要一个迭代器。您希望它遍历最后一个数组。当它到达该数组的末尾时,递增其在倒数第二个数组中的当前位置并返回到最后一个数组的开头。

    使用 C#s yield return 语法的伪代码:

    foreach n1 in a1
        foreach n2 in a2
            foreach n3 in a3
                yield return (n1, n2, n3)
    

    编辑:如果集合的数量不同,您可以使用某种形式的递归:

    function next(list)
        firstArray = list.first
        iterator = iterator(list.rest)
        if !iterator
            foreach i in firstArray
                yield return i
        else
            foreach i in firstArray
                while (iterator.hasNext)
                    yield return (i, iterator.next)
    

    考虑传入长度为 1 的列表时的行为,然后考虑长度为 2 的列表的行为,并确信它确实有效。

    【讨论】:

    • 哎呀,我忘了提到套数是可变的
    • @James 在某个地方,您将不得不为自己做一些跑腿工作。虽然 Anon 没有解决集合数量可变的事实,但这是您应该能够自己解决的问题,因为其他人都在给您。
    • 公平地说,基于具有嵌套循环的解决方案实现可变数量的集合通常很重要。
    猜你喜欢
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多