如果以随机顺序给出数组,则必须输出转换为循环排序数组所需的最小交换次数。
e.g。给出的数组是3 5 4 2 1
所以第一次交换将是5< - > 4结果:3 4 5 2 1 第二次交换将是2< - > 1结果:3 4 5 1 2(最终)
输出:2
我无法理解这个问题背后的逻辑。
添加更多: 只能在相邻元素之间进行交换,数字介于1到N之间
答案 0 :(得分:5)
好吧,不知道它是否是最好的算法,但我能想到一个O(n ^ 2)解决方案:
首先,忽略循环数组的可能性。让我们解决一个更简单的问题:对数组进行排序的最小交换次数是多少。
这里要小心,因为这不是排序算法。基于比较的排序算法将具有至少O(n log n)
的最坏情况。在此问题中,您需要的最大交换次数为n
。
为什么呢?因为它是您可以实现的最大permutation cycle size。您需要的最小交换数量恰好是排列周期大小减去1。我的意思是你可以将数组的任何排列表示为排列周期,例如:
3 2 1 4 5
- > (2)(4)(5)(1 3)
对于大小为1的排列周期,您不需要任何交换。对于大小为2的置换周期,您只需要1个交换。这可以缩写为:
2 3 4 5 1
- > (1 2 3 4 5)
忽略此数组已经循环排序,此数组完全混乱。为了正常排序,我需要4个交换,基本上将1移动到它的正常位置。
计算排列周期非常简单,只需跟踪数字到数组排序的位置即可。使用前面的例子
3 2 1 4 5
A[0]
; A[0]==3
和3将是排序数组中的第3个元素,所以是第3个位置; 因为A[2]==1
和1将是......,所以跟随第一个位置。由于我们已经在那里,我们有一个大小为2的周期;
在下一个未访问的位置(1)再次开始
A[1]==2
处于正确的位置,所以我们不需要做任何事情,这里我们有一个大小为1的周期。
依此类推......
这个算法是O(n),但是因为我们需要为每个可能位置的数组做这个(因为它是圆形的),我们会做n次,所以,整个算法是O(n ^ 2)。
<强> UPDATE;一些python代码显示我的算法:
def offset_swaps(A, S, offset):
visited = [False]*len(A)
swaps = 0
for i in xrange(len(A)):
if visited[i]: continue
cycle, current = 0, i
while not visited[current]:
cycle += 1
visited[current] = True
current = (S[A[current]] + offset) % len(A)
swaps += cycle - 1
return swaps
def number_of_swaps(A):
S = {x:i for i,x in enumerate(sorted(A))}
min_swaps = len(A)
for i in xrange(len(A)):
min_swaps = min(min_swaps, offset_swaps(A, S, i))
return min_swaps
print number_of_swaps((3, 5, 4, 2, 1))
答案 1 :(得分:1)
我认为这里的方法应该是 - 将所有数字排序到辅助数组中。然后,对于每个循环移位,计算使原始阵列达到该循环移位所需的交换次数。选择最小的那些。
要找到将数组A到阵列B所需的最小数量的交换,只需计算交换值的数量(即,值a在A的值b左侧,但在数组B中则相反)。这个问题对于计算给定数组中的反转是相同的,并且可以在O(n*log(n))
中再次使用修改的合并排序来解决。
我的方法的复杂性是O(n^2*log(n))
(因为你对大小为n的数组的所有循环移位进行合并排序)。
我想不出更快解决问题的方法。
答案 2 :(得分:0)
假设:
步骤:
这是O(N)。
更新:我已更新算法以考虑多个轨道。在处理每个轨道时,最终交换放置两个元素而不仅仅是1.
我怀疑轨道的数量在任何旋转下都是不变的,这会有效地简化算法,但不会影响它的复杂性,它保持在O(N)。
答案 3 :(得分:0)
def number_of_swaps(A):
l=len(A)
if l < 2:
return 0
S1={x:i for i,x in enumerate(A)}
pos_of_0=S1[0]
pos_of_N=S1[l-1]
if pos_of_0 > 0:
if pos_of_N != (l-1):
if pos_of_N < pos_of_0:
n=(pos_of_0+(l-1)-pos_of_N-1)
else:
n=(pos_of_0+(l-1)-pos_of_N)
else:
n=(pos_of_0)
else :
n=(l-pos_of_N-1)
A.remove(0)
A.remove(l-1)
B=[x-1 for x in A ]
return n+number_of_swaps(B)
def min_number_of_swaps(A):
B=sorted(A)
swaps=[]
for i in range(len(A)):
if i == 0:
C=B
else:
C=B[-i:]+B[0:len(A)-i]
S = {x:i for i,x in enumerate(C)}
D=[S[i] for i in A]
swaps.append(number_of_swaps(D))
return min(swaps)
print min_number_of_swaps([8,5,7,1,2,4,3,6])
7
以上代码是解决问题复杂度O(N ^ 3)
的递归方法 已编辑代码,仅打印最小数量的交换。