在输入上我有一个“n”数字,这是排列的大小,我必须打印所有可能的排列包含n个数字(从1做n),但我必须拒绝有“231计划”的人
<231>“231 scheme”意味着在置换中我们可以找到将应用于不等式z(1 <2 <3)的这样的三个连续数字(x,y,z)。所以,例如对于n = 4,我们有4个! = 24个排列。我们拒绝了其中的九个......
...并打印其他十五个可能性。
好的,这就是问题所在。我已经花了很多时间考虑这个任务。我已经想到了这样的事情:
我们可以生成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”,我们从最终答案中拒绝。
我非常感谢任何评论,想法和提示。我意识到我的想法可能毫无用处,但这是我所拥有的最好的。那么还有其他(可能更聪明和/或更复杂)的方式吗?
答案 0 :(得分:1)
你有正确的想法。通过将1
添加到n
,迭代地构建您的排列。添加i
后,您只需检查您希望避免的模式是否存在 i
。
例如,如果模式为231
,则检查i
左侧的任何内容是否大于i
右侧的任何内容。
如果要打印所有结果而不是生成它们(这可以避免存储问题),那么您可以按字典顺序浏览排列。扫描前缀,如果在任何时候存在模式,例如在第一个k
字母中,然后转到下一个前缀。这将加快迭代速度。
答案 1 :(得分:0)
这可能是一顶旧帽子,但只需添加一下:避免231的排列数是加泰罗尼亚数,可以估计为O(2 ^(2n))(它们也有一个很好的封闭公式) 。确切地说,对于n = 15,我们将有9,694,845个数字。
我们可以为置换建立递归,同时避免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;
您可以使用动态编程/记忆进一步完善该算法。