我正在寻找一种方法来检查2 排列(由列表表示)是否属于相同parity 。请注意,我不感兴趣,如果它们甚至或奇数奇偶校验,只是相等。
我是Python的新手,下面给出了我的天真解决方案作为回复。我期待Python专家向我展示一些很酷的技巧,以便在更小,更优雅的Python代码中实现相同的目标。
答案 0 :(得分:6)
以下是我对代码的调整
这是
def arePermsEqualParity(perm0, perm1):
"""Check if 2 permutations are of equal parity.
Assume that both permutation lists are of equal length
and have the same elements. No need to check for these
conditions.
"""
perm1 = list(perm1) ## copy this into a list so we don't mutate the original
perm1_map = dict((v, i) for i,v in enumerate(perm1))
transCount = 0
for loc, p0 in enumerate(perm0):
p1 = perm1[loc]
if p0 != p1:
sloc = perm1_map[p0] # Find position in perm1
perm1[loc], perm1[sloc] = p0, p1 # Swap in perm1
perm1_map[p0], perm1_map[p1] = sloc, loc # Swap the map
transCount += 1
# Even number of transpositions means equal parity
return (transCount % 2) == 0
答案 1 :(得分:6)
如果我们结合两种排列,当每个排列具有相同的奇偶校验时,结果将具有偶校验,如果它们具有不同的奇偶校验,则奇校验。因此,如果我们解决奇偶校验问题,那么比较两种不同的排列是微不足道的。
奇偶校验可以确定如下:选择一个任意元素,找到置换移动到的位置,重复直到你回到你开始的位置。您现在已经找到了一个循环:排列将所有这些元素围绕一个位置旋转。您需要一个小于循环中元素数量的交换来撤消它。现在选择你尚未处理的另一个元素并重复,直到你看到每个元素。请注意,总的来说,每个元素需要一次交换,每个周期需要一次交换。
时间复杂度是置换大小的O(N)。请注意,虽然我们在循环中有一个循环,但内循环只能对排列中的任何元素迭代一次。
def parity(permutation):
permutation = list(permutation)
length = len(permutation)
elements_seen = [False] * length
cycles = 0
for index, already_seen in enumerate(elements_seen):
if already_seen:
continue
cycles += 1
current = index
while not elements_seen[current]:
elements_seen[current] = True
current = permutation[current]
return (length-cycles) % 2 == 0
def arePermsEqualParity(perm0, perm1):
perm0 = list(perm0)
return parity([perm0[i] for i in perm1])
另外,只是为了好玩,这是基于Wikipedia中定义的奇偶校验函数的效率低得多但短得多的实现(对于偶数返回True,对于奇数返回False):
def parity(p):
return sum(
1 for (x,px) in enumerate(p)
for (y,py) in enumerate(p)
if x<y and px>py
)%2==0
答案 2 :(得分:4)
我天真的解决方案:
def arePermsEqualParity(perm0, perm1):
"""Check if 2 permutations are of equal parity.
Assume that both permutation lists are of equal length
and have the same elements. No need to check for these
conditions.
"""
transCount = 0
for loc in range(len(perm0) - 1): # Do (len - 1) transpositions
if perm0[loc] != perm1[loc]:
sloc = perm1.index(perm0[loc]) # Find position in perm1
perm1[loc], perm1[sloc] = perm1[sloc], perm1[loc] # Swap in perm1
transCount += 1
# Even number of transpositions means equal parity
if (transCount % 2) == 0:
return True
else:
return False
答案 3 :(得分:4)
上一个答案的次要变体 - 复制perm1,并保存数组查找。
def arePermsEqualParity(perm0, perm1):
"""Check if 2 permutations are of equal parity.
Assume that both permutation lists are of equal length
and have the same elements. No need to check for these
conditions.
"""
perm1 = perm1[:] ## copy this list so we don't mutate the original
transCount = 0
for loc in range(len(perm0) - 1): # Do (len - 1) transpositions
p0 = perm0[loc]
p1 = perm1[loc]
if p0 != p1:
sloc = perm1[loc:].index(p0)+loc # Find position in perm1
perm1[loc], perm1[sloc] = p0, p1 # Swap in perm1
transCount += 1
# Even number of transpositions means equal parity
if (transCount % 2) == 0:
return True
else:
return False
答案 4 :(得分:2)
这是稍微重构的Weeble's answer:
def arePermsEqualParity(perm0, perm1):
"""Whether permutations are of equal parity."""
return parity(combine(perm0, perm1))
def combine(perm0, perm1):
"""Combine two permutations into one."""
return map(perm0.__getitem__, perm1)
def parity(permutation):
"""Return even parity for the `permutation`."""
return (len(permutation) - ncycles(permutation)) % 2 == 0
def ncycles(permutation):
"""Return number of cycles in the `permutation`."""
ncycles = 0
seen = [False] * len(permutation)
for i, already_seen in enumerate(seen):
if not already_seen:
ncycles += 1
# mark indices that belongs to the cycle
j = i
while not seen[j]:
seen[j] = True
j = permutation[j]
return ncycles
答案 5 :(得分:2)
带有字典的解决方案被窃听。 这是调试版本:
def arePermsEqualParity(perm0, perm1):
"""Check if 2 permutations are of equal parity.
Assume that both permutation lists are of equal length
and have the same elements. No need to check for these
conditions.
"""
perm1 = list(perm1) ## copy this into a list so we don't mutate the original
perm1_map = dict((v, i) for i,v in enumerate(perm1))
transCount = 0
for loc, p0 in enumerate(perm0):
p1 = perm1[loc]
if p0 != p1:
sloc = perm1_map[p0] # Find position in perm1
perm1[loc], perm1[sloc] = p0, p1 # Swap in perm1
perm1_map[p0], perm1_map[p1] = loc, sloc # Swap the map
transCount += 1
# Even number of transpositions means equal parity
return (transCount % 2) == 0
唯一的区别是字典中的交换没有正确。
答案 6 :(得分:0)
我的直觉告诉我,只计算两种排列之间的差异,就会比交换的数量多一个。这反过来会给你平价。
这意味着您根本不需要在代码中进行交换。
例如:
ABCD, BDCA.
存在三个差异,因此需要两个互换来将一个互换到另一个,因此您甚至可以进行奇偶校验。
另:
ABCD, CDBA.
有四个差异,因此有三个互换,因此奇数奇偶校验。
答案 7 :(得分:0)
def equalparity(p,q):
return sum([p[q[i]] > p[q[j]] for i in range(len(p)) for j in range(i)]) % 2 == 0