给定L
不同元素的两个排列A
和B
,L
是偶数的,让我们称这些置换为“对称的”(因为缺少更好的术语),如果存在n
和{m > n
,例如(在python表示法中):
- A[n:m] == B[L-m:L-n]
- B[n:m] == A[L-m:L-n]
- all other elements are in place
非正式地考虑
^{pr2}$取它的任何部分,例如1 2
。它从第二个索引开始,长度为2。现在取一个与之对称的切片:它在倒数第二个索引处结束,也有2个字符长,因此它是5 6
。交换这些切片
B = 0 5 6 3 4 1 2 7
现在,A
和{n=1, m=3
)。另一方面
A = 0 1 2 3 4 5 6 7
B = 1 0 2 3 4 5 7 6
不是“对称的”(不存在具有上述属性的n,m
)。在
我如何用python编写一个算法来发现两个给定的排列(=列表)是否是“对称的”,如果是,则找到n
和{L
(因为奇数可以通过消除中间固定元素而简单地简化为偶数),并假设输入正确(set(A)==set(B), len(set(A))==len(A)
)。在
(我对所有可能的对称毫无疑问,但我在寻找更聪明、更快的东西)。在
有趣的事实:给定的L
的对称置换数是Triangular number。在
赏金更新:这里有很多很好的答案。@Jared Goguen's solution似乎是最快的。在
最终时间安排:
testing 0123456789 L= 10
test_alexis ok in 15.4252s
test_evgeny_kluev_A ok in 30.3875s
test_evgeny_kluev_B ok in 27.1382s
test_evgeny_kluev_C ok in 14.8131s
test_ian ok in 26.8318s
test_jared_goguen ok in 10.0999s
test_jason_herbburn ok in 21.3870s
test_tom_karzes ok in 27.9769s
我重写了代码,没有一些复杂性(和错误)。在
实现既优雅又高效。在
break
intoelse: return
结构确保函数在最快的时间点返回。它们还验证n
和{显式地比较切片也会在计算结果为
False
时短路。在最初,我通过将
^{pr2}$b
转换为a
来检查是否存在置换:但这比显式比较切片慢。让我知道,如果算法不能说明自己,我可以提供进一步的解释(甚至可以证明)为什么它工作,它是最小的。在
以下是问题的工作解决方案:
正如你所提到的,虽然这个想法看起来很简单,但实际上是一个相当棘手的想法。然而,一旦我们看到了模式,实现就很简单了。在
解决方案的中心思想是这样一行:
^{pr2}$所有其他行要么直接从问题语句中翻译代码,要么进行优化以提高计算效率。在
要找到解决方案,需要几个步骤:
首先,我们需要将每个both list})。每个半列表将包含原始列表的一半成员:
^{3}$A
和listB
拆分为两个半列表(称为Al
,Ar
,Bl
,和{其次,为了使评估有效,这里的目标是找到我称之为枢轴索引的东西,以确定列表(索引)中的位置是否值得评估,以检查列表是否对称。这个轴索引是找到一个有效的解决方案的中心思想。所以我会尽量详细说明一下:
考虑
A
列表的左半部分,假设您有一个这样的成员:我们可以想象对于上述列表,存在一个对应的索引列表,如下所示
(注意:我之所以提到想象一个对应的索引列表是为了便于解释)
同样,我们可以想象其他三个列表可能有相似的索引列表。让我们分别将它们命名为},它们的成员都与
iAr
、iBl
、和{iAl
相同。在为了解决这个问题,列表的索引才是真正重要的。在
我的意思是:假设我们有两个参数:
i
,我将使用符号^
表示当前的i
)j
,我将使用符号==
来直观地表示它的长度值)对于
iAl
中的索引元素的每个评估,则每个评估将意味着:现在,让我们以一个求值为例,当
i = 0
和j = 1
时。评估的说明如下:为了使那些索引}必须具有相同的相同的项目值,但长度不相同,但索引不相同
i
和长度j
得到进一步的评估,那么对应的{例如,对于上述情况,这是两个列表
Al-Br
的一个可能的“对称”排列(稍后我们将考虑另两个列表Ar-Bl
):在这一刻,值得注意的是
这就是你使算法更有效的地方;也就是说,通过在所有可能的情况中只选择评估少数可能的情况。如何找到少数可能的病例?在
了解了这些之后,让我们进一步看看在评估过程中是否可以看到更多模式。在
现在考虑长度的影响(
j
)。例如,如果我们要从索引0
求值,但是长度是2
,那么与长度为1
时相比,对应列表需要有不同的索引k
或者,对于上面的例子,福克斯
i = 0
和y = 2
真正重要的是:请看一下,上面的模式与
i = 0
和y = 1
时不同,在示例中,0
值的索引位置发生了移动:因此,长度偏移,其中必须检查对应列表的索引。在第一种情况下,当}时,
i = 0
和y = 1
,那么k = 5
。但是在第二种情况下,当i = 0
和{k = 4
。因此,当我们将一个固定的索引j
(在本例中是0
)的长度j
更改为对应列表索引k
时,我们发现了轴索引关系。在现在,考虑长度固定的索引
i
对对应列表索引j
的影响。例如,让我们将长度固定为y = 4
,然后对于索引i = 0
,我们有:在上面的例子中,可以看出,我们需要计算给定的
i
和j
的可能性,但是如果索引i
更改为长度相同的j = 4
,则:注意,我们只需要评估2的可能性。因此,指数的增加
i
减少了可能要评估的案例数量!在在找到上述所有模式之后,我们几乎找到了使算法工作所需的所有基础。但要完成这一点,我们需要找到给定的
Al-Br
对中出现的索引与同一Ar-Bl
对中的索引之间的关系。在现在,我们实际上可以看到它们只是镜像我们在
Al-Br
对中发现的关系!在(IMHO,这真是太美了!所以我认为“对称”排列这个词离事实并不遥远)
例如,如果我们用
i = 0
和y = 2
来计算Al-Br
对然后,为了使其对称,我们必须有相应的
Ar-Bl
:Al-Br
对的索引是镜像(或对称于)Ar-Bl
对的索引!在因此,结合我们在上面找到的所有模式,我们现在可以找到用于评估}的轴索引。在
Al
、Ar
、Bl
、和{将上述所有知识放入代码中,下面是要检查对称性的
for-loop
Python代码:这就是对称测试!在
(好吧,这是一个相当大的挑战,我要花相当长的时间才能弄清楚)
我试着为这个任务实现3种不同的算法。它们都具有O(N)时间复杂度,需要O(1)个额外的空间。有趣的事实:所有其他答案(目前已知)实现了其中的2个算法(尽管它们并不总是保持最佳的渐近时间/空间复杂度)。下面是每个算法的高级描述:
算法A
算法B
算法C
每种算法的步骤1有两种可选的实现:(1)使用itertools,和(2)使用普通循环(或列表理解)。itertools对于长列表是有效的,但是对于短列表则相对较慢。在
这是算法C,第一步是用itertools实现的。它看起来比其他两种算法更简单(在本文末尾)。而且它的速度非常快,即使对于短名单:
这可以主要使用itertools来完成:
^{pr2}$@j_random_hacker已经在OP评论中提供了该算法的高级描述。以下是一些细节:
从比较列表开始:
^{3}$然后找出相等/不相等间隔之间的边界:
然后确定非相等元素的范围:
然后检查是否正好有两个范围(特别是当两个范围在中间相交时),范围本身是对称的,它们的内容也是对称的。在
另一种选择是使用itertools只处理每个列表的一半。这使得算法更简单(也更快),因为不需要处理特殊情况:
相关问题 更多 >
编程相关推荐