避免排列模式 - 打印所有排列而不使用231方案

时间:2012-05-06 15:25:02

标签: algorithm permutation

在输入上我有一个“n”数字,这是排列的大小,我必须打印所有可能的排列包含n个数字(从1做n),但我必须拒绝有“231计划”的人

<231>“231 scheme”意味着在置换中我们可以找到将应用于不等式z(1 <2 <3)的这样的三个连续数字(x,y,z)。

所以,例如对于n = 4,我们有4个! = 24个排列。我们拒绝了其中的九个......

  • 4231,2431,2341,2314 - 因为他们有231
  • 2413,3241 - 因为他们有241
  • 3412,3421 - 因为他们有341(和342)
  • 1342 - 因为它有342

...并打印其他十五个可能性。

好的,这就是问题所在。我已经花了很多时间考虑这个任务。我已经想到了这样的事情:

我们可以生成n = 3的排列,拒绝231然后(对于n = 4)基于先前生成的排列生成所有可能性。

所以我会选择132个排列。现在我们在所有可能的方式上“插入”4: 4132, 1432, 1342, 1324。 我们可以肯定地说,第一个和最后一个排列都很好,所以我们必须更接近另外两个。我的想法是找到站在“4”左侧的数字中的最高数字,并且从站在“4”右侧的数字中找到最小数字。 如果left_max&gt; right_min,我们有“231计划”。

例如排列1342:left_max = 3,right_min = 2,所以它是正确的“231”,我们从最终答案中拒绝。

我非常感谢任何评论,想法和提示。我意识到我的想法可能毫无用处,但这是我所拥有的最好的。那么还有其他(可能更聪明和/或更复杂)的方式吗?

2 个答案:

答案 0 :(得分:1)

你有正确的想法。通过将1添加到n,迭代地构建您的排列。添加i后,您只需检查您希望避免的模式是否存在 i

例如,如果模式为231,则检查i左侧的任何内容是否大于i右侧的任何内容。

如果要打印所有结果而不是生成它们(这可以避免存储问题),那么您可以按字典顺序浏览排列。扫描前缀,如果在任何时候存在模式,例如在第一个k字母中,然后转到下一个前缀。这将加快迭代速度。

答案 1 :(得分:0)

这可能是一顶旧帽子,但只需添加一下:避免231的排列数是加泰罗尼亚数,可以估计为O(2 ^(2n))(它们也有一个很好的封闭公式) 。确切地说,对于n = 15,我们将有9,694,845个数字。

使用加泰罗尼亚语数字的递归公式 enter image description here

我们可以为置换建立递归,同时避免231:

all_perms(n):
    if (n=0) return [1];
    out = [];
    for i=1,...,n:
        for perm1, perm2 in all_perms(i-1), all_perms(n-i):
            increase all elements in perm2 by i-1;
            append n to perm1 (from the right), then append perm2 to that (from the right);
        add the result of appending into out;

您可以使用动态编程/记忆进一步完善该算法。