if an array is given in random order , you have to output the minimum number of swaps required to convert into cyclic sorted array.
e.g. array given is 3 5 4 2 1
Well, don't know if it is the best algorithm available, but I can think of a O(n^2) solution:
First, ignore the possibility of the cyclic array. Let's solve a simpler problem: what is the minimum number of swaps to sort an array.
Be careful here, because this isn't about sorting algorithms. A comparation-based sorting algorithm would have a worst-case of at least O(n log n)
. In this problem, the maximum number of swaps you need is n
.
Why? Because it's the maximum permutation cycle size you can achieve. The minimum number of swaps you need is exactly the permutation cycle size minus one. I mean you can represent any permutation of the array as a permutation cycle, e.g.:
3 2 1 4 5
-> (2)(4)(5)(1 3)
For the permutations cycles of size 1, you don't need any swap. For the permutation cycle of size 2, you need exactly 1 swap. This scales as:
2 3 4 5 1
-> (1 2 3 4 5)
Ignoring this array is already cyclic-sorted, this array is tottaly messed. To sort it normally, I would need 4 swaps, basically moving the 1 to it's normal position.
Calculating the permutation cycles is pretty easy, it's just a matter of following the number to where it should be if the array was sorted. Using the previous examples
3 2 1 4 5
A[0]
;A[0]==3
, and 3 would be the 3rd element in sorted array, follows to 3rd position;Because A[2]==1
, and 1 would be..., follows to 1st position. As we were already there here we have a cycle of size 2;
Starts again at next unvisited position (1)
A[1]==2
is in it's right position, so we don't need to do anything, here we have a cycle of size 1.
and so forth...
This algorithm is O(n), but as we need to do this for the array starting in every possible position (because it is circular), we would do it n times, so, the entire algorithm is O(n^2).
UPDATE; some python code to show my algorithm:
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))
Assuming:
Steps:
This is O(N).
Update: I have updated the algorithm to account for multiple orbits. In processing each orbit, the final swap places two elements instead of just 1.
I suspect that the number of Orbits is invariant under any rotation, which would simplify the algorithm considerbly but would not affect it's complexity, which remains at O(N).
I think the approach here should be - sort all the numbers into a helper array. Then for each cyclic shift calculate the number of swaps needed to get the original array to this cyclic shift. Choose the minimal of those.
To find minimal number of swaps required to get array A to array B simply count the number of interchanged values(i.e. value a is on the left of value b in A but vice versa in array B). This problem is equivelent to counting the inversions in a given array and can be solved using modified merge sort again in O(n*log(n))
.
The complexity of my approach is O(n^2*log(n))
(because you do a merge sort for all cyclic shifts of an array of size n).
I can not think of a faster solution for your problem.
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
Above code isrecursive approach to solve the problem Complexity O(N^3)
code has been edited to print only min number of swaps.