这是一个面试问题,我没有回答,但仍然对如何解决感到好奇。
你有大家庭的N人,分别为1,2,3,......,N岁。 你想拍一张你这个大家庭的照片。你们所有的家人都会排成一排。
“我,这个家庭的朋友,建议如下安排家人:”
输入:整数N,1≤N≤55。
输出:摄影师可拍摄的照片数量。
示例 - >输入:4,输出:4
符合条件的数组:
[1,2,3,4] [1,2,4,3] [1,3,2,4-] [1,3,4,2]
另一个例子:
输入:5输出:6
符合条件的数组:
[1,2,3,4,5] [1,2,3,5,4] [1,2,4,3,5] [1,2,4,5,3] [1, 3,2,4,5] [1,3,5,4,2]
我在Ruby中选择了这个问题,通过生成每个排列并过滤它们来解决这个问题,首先检查条件#1,确保数组的第一个条目== 1,这很好,快。
其次是从左到右走每个阵列并确保每对的绝对值差异不超过2.这是可怕的和缓慢的。
我的实现,当N>时变得很慢9.因为它正在排序300k排列。 从那里开始的时间是二次的(我相信,仍然可以解决这个问题)。
我应该如何改善这种情况?
我不是真的在这里寻找代码示例,更多的想法,应该使用哪种算法来有效地排列排列?我应该写自己的排列(可能是的)。
在这些方面,我确实复制了此版本的QuickPerm https://stackoverflow.com/a/2390969/1265528
在results << yield(a)
附近添加一个条件,只选择以1开头的数组,但我不确定如何最好地实现上述其他条件。
修改
这是令人难以置信的令人失望的解决方案。
我真的想弄清楚如何生成排列,而不是表示可能的正确排列数的整数。 -
def number_of_possible_perms(n_persons)
array = []
array[0] = 0
array[1] = array[2] = 1
for i in 3..n_persons
array[i] = array[i-1] + array[i-3] + 1
end
return array[n_persons]
end
答案 0 :(得分:8)
如果我们绘制出可能的转换,那么应该更清楚地说明如何解决这个问题:
2 6---8
/|\ /|\ /|\
1 | 4 | 7 | 10...etc
\|/ \|/ \|/
3---5 9
让每个数字只接触一次并从1开始的路径总数为C_n,其中n是节点数。让我们考虑一些可能的情况:
现在假设n&gt; 3.让我们考虑一些可能的序列:
所以我们现在有C_n = C_(n-1)+ C_(n-3)+ 1.
答案 1 :(得分:0)
我不确定是否存在针对此问题的优化算法,但我想到的是一种蛮力方法backtracking。
它比迭代所有可能的预先计算的排列更有效,因为如果找到第一个非匹配对,它可以立即停止。因此,它可以修剪搜索空间的大部分(换句话说,它不必查看所有N!排列)。
答案 2 :(得分:0)
创建一个方法f
,它接受N
并返回可能数组的数组。在这样做时,使用递归。当N
= 1
时,您知道可能性仅为[1]
,因此输出应为[[1]]
。否则,请计算f(N - 1)
。要从f(N)
获取N
,请考虑f(N - 1)
中每个数组中可以插入哪些位置{{1}}。
答案 3 :(得分:0)
我会这样做。
<强>条款强>
N
:人数A(n,i)
:满足第一个n
家庭成员之间排序要求(“可行排列”)的所有排列的集合,以使人年龄i
为最后一个,{{ 1}}。<强>目标强>
确定2 <= i <= n
取消所有A(N,i)
的联合。
<强>算法强>
i=2..N
只有一种方式可以命令1和2人:
n = 2
以及两种订购前3种方式:
A(2,2) = { [1,2] }
n = 3
当我们考虑前四个时,我们开始变得更有趣了。最初,无视相邻成员年龄差异最多两年的要求。
A(3,2) = { [1,3,2] }
A(3,3) = { [1,2,3] }
n = 4
注意这些集合是如何确定的。考虑A(4,2) = { [1,4,3,2], [1,3,4,2] }
A(4,3) = { [1,4,2,3], [1,2,4,3] }
A(4,4) = { [1,3,2,4], [1,2,3,4] }
。我们在A(4,2)
中采用单个排列,并将A(3,2)
插入两个可能的位置。
我们接下来删除所有不满足相邻年龄差异要求的组合,并留下以下内容:
4
同样,首先计算A(4,2) = { [1,3,4,2] }
A(4,3) = { [1,2,4,3] }
A(4,4) = { [1,3,2,4], [1,2,3,4] }
n=5
的集合,而不参考相邻的年龄要求:
n=5
请注意这些集合是如何从A(5,2) = { [1,5,3,4,2], [1,3,5,4,2], [1,3,4,5,2] }
A(5,3) = { [1,5,2,4,3], [1,2,5,4,3], [1,2,4,5,3] }
A(5,4) = { [1,5,3,2,4], [1,3,5,2,4], [1,3,2,5,4],
[1,5,2,3,4], [1,2,5,3,4], [1,2,3,5,4] }
A(5,5) = { [1,3,4,2,5], [1,2,4,3,5], [1,3,2,4,5], [1,2,3,4,5 }
,A(4,2)
,A(4,3)
和A(4,4)
组合生成的。要计算A(5,2)
,例如,对于A(5,2)
中的每个枚举(只有一个),我们会在第一个和最后一个之后的每个位置插入A(4,2)
。
现在删除所有可行的permations,留下我们:
5
以这种方式继续,直到为A(5,2) = { [1,3,5,4,2], [1,3,4,5,2] }
A(5,3) = { }
A(5,4) = { [1,3,5,2,4], [1,2,3,5,4] }
A(5,5) = { [1,2,4,3,5], [1,3,2,4,5], [1,2,3,4,5 }
计算A(N,i)
。
如果i=2,...N
,可行的排列将是这四组的结合:
N => 5
我希望通过一次消除一组排列来应用额外的逻辑来加速计算。