(任何语言)使用交换查找向量中元素的所有排列

时间:2013-11-28 18:17:02

标签: algorithm permutation swap multiple-languages

我今天在实验室会议上被问到这个问题。

我们可以想象一个包含元素1 ... N-1的向量,长度为N.是否存在生成所有排列或向量中元素顺序的算法(系统)方法。一种提出的方​​法是交换随机元素。显然,如果存储所有先前生成的排列以供将来参考,这将是有效的,但是这显然是一种非常低效的方法,无论是空间方式还是时间方式。

顺便说一下这样做的原因是从向量中的特殊位置移除特殊元素(例如,为零的元素),其中不允许这样的元素。因此,随机方法并不是那么荒谬,但想象一下元素数量很大的情况和可能的排列数(在任何“特殊位置”中都没有“特殊元素”)低。

我们试图在N = 5的情况下解决这个问题:

x = [1, 2, 3, 4, 5]

首先,交换元素4和5:

x = [1, 2, 3, 5, 4]

然后交换3和5:

x = [1, 2, 4, 5, 3]

然后是3和4:

x = [1, 2, 5, 4, 3]

最初我们认为使用两个索引ix和jx可能是一个可能的解决方案。类似的东西:

ix = 0;
jx = 0;

for(;;)
{
    ++ ix;

    if(ix >= N)
    {
        ix = 0;
        ++ jx;

        if(jx >= N)
        {
            break; // We have got to an exit condition, but HAVENT got all permutations
        }
    }

    swap elements at positions ix and jx

    print out the elements
}

这适用于N = 3的情况。但是对于更高的N,它不起作用。我们认为这种方法可能是正确的。我们试图扩展到使用3个索引的方法,由于某种原因我们认为可能是解决方案:使用第3个索引来标记索引ix开始或结束的向量中的位置。但我们陷入困境,并决定向SO社区寻求建议。

1 个答案:

答案 0 :(得分:2)

执行此操作的一种方法是,对于第一个字符e

  • 首先递归下一个元素
  • 然后,对于e2之后的每个元素e
    • 交换ee2
    • 然后递归下一个元素
    • 撤消交换

的伪代码:

permutation(input, 0)

permutation(char[] array, int start)
    if (start == array.length)
        print array

    for (int i = start; i < array.length; i++)
        swap(array[start], array[i])
        permutation(array, start+1)
        swap(array[start], array[i])

通过此函数的主调用,它将尝试第一个位置的每个字符,然后递归。简单地循环遍历所有字符在这里工作是因为我们之后撤消了每次交换,所以在递归调用返回之后,我们保证会回到我们开始的地方。

然后,对于每个递归调用,它会尝试第二个位置中的每个剩余字符。等等。

Java live demo