10

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

so the first swap will be 5<-->4 result : 3 4 5 2 1 second swap will be 2<-->1 result : 3 4 5 1 2 (final)

output : 2

i am not able to get the logic behind this problem.

adding some more : swap only possible between adjacent elements and numbers are between range 1 to N

user2161522
  • 203
  • 3
  • 6
  • 2
    Are the numbers in the array always going to be sequential? – DPenner1 Mar 12 '13 at 15:18
  • Do you only require the number of swaps, and not the actual swaps themselves? – Pieter Geerkens Mar 12 '13 at 15:43
  • Look up "Towers of Hanoi". – Hot Licks Mar 12 '13 at 16:26
  • if we sort the array in nlog(n) (merge sort) it should work. are you looking for better complexity ? – aked Mar 12 '13 at 17:27
  • the numbers will be in the range of 1 to N. swap is only possible between adjacent elements. – user2161522 Mar 12 '13 at 17:52
  • I am working on this problem but do not know the exact definition for "cyclic sorted array." Can you help me understand -- are these considered cyclic sorted arrays: `[3,5,1,2,4] , [5,6,3,4,1,2]`? What is the solution for `[1,2,3,4,5]` can it be `[1,2,5,3,4]`? – גלעד ברקן Mar 13 '13 at 01:00
  • You didn't say swap was only possible between adjacent elements. – Juan Lopes Mar 13 '13 at 19:58
  • @groovy : nope the examples you mentioned are incorrect . cyclicsorted array is like ring counter. it starts from some value V where lower_end = – user2161522 Mar 15 '13 at 05:02
  • Do you consider the first and last elements to be adjacent? Does the sort have to be ascending or can it be in either direction? For example, what output do you expect for the input `5 2 3 4 1`? What about `5 4 3 2 1`? – jerry Mar 15 '13 at 20:19

4 Answers4

5

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

  • Starts at A[0];
  • Because 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))
Juan Lopes
  • 10,143
  • 2
  • 25
  • 44
  • @Knoothe sorry I forgot to remove this comment it is wrong indeed – Ivaylo Strandjev Mar 12 '13 at 16:13
  • thanks but I am not sure about the solution you provided will be able to give a result. I tried to solve it using modified bubble sort but not able to guess the condition to be a valid swap. – user2161522 Mar 12 '13 at 16:24
  • O(N^2) is clearly inferior to a plain O(N log N) sort, or (constraints being met) an O(N) Radix sort. – Pieter Geerkens Mar 13 '13 at 18:16
  • I am impressed by your deft answers on different questions, even as I am somewhat limited in my ability to understand some of them. I am curious what you might think of my idea: http://stackoverflow.com/questions/15364607/given-an-array-of-integers-in-random-order-you-have-to-find-the-minimum-number-o/15425896#15425896 – גלעד ברקן Mar 15 '13 at 06:17
  • @PriyankBolia On the original statement (any 2-element swap was allowed), consider (3, 5, 6, 4, 2, 1): swap 1 -> 4, then 4 -> 3, it becomes (4, 5, 6, 1, 2, 3). – Juan Lopes Mar 15 '13 at 15:31
1

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.

Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • Not exactly. Ignore the cyclic requirement for a moment. `2 3 1 5 4` have all values misplaced, but you only need 3 swaps to sort it (1 with 3, then 1 with 2, then 4 with 5). But `2 3 4 5 1` also have all values misplaced, and you need 4 swaps to sort it (slide the 1 to its right position). – Juan Lopes Mar 12 '13 at 15:29
  • @JuanLopes I said you need to try all the cyclic shifts and choose the one that requires the least number of swaps. I am not sure what does your `not exactly` refer to – Ivaylo Strandjev Mar 12 '13 at 15:31
  • Yes, but you didn't provide a solution on how to count the minimum number of swaps. Just seeing how many elements are displaced isn't enough. You need to calculate the permutation cycles. – Juan Lopes Mar 12 '13 at 15:32
  • @JuanLopes minimal number of swaps is equal to the number of inversions in the array just as I have stated – Ivaylo Strandjev Mar 12 '13 at 15:33
  • Would you care to explain how to calculate this number of inversions? – Juan Lopes Mar 12 '13 at 15:34
  • @JuanLopes I have already mentioned it is done using modified merge sort in my answer. You can google it but otherwise here is an answer I think pretty much shows how to do it: http://stackoverflow.com/questions/337664/counting-inversions-in-an-array/6424847#6424847 – Ivaylo Strandjev Mar 12 '13 at 15:38
  • This problem is different. If we count all pairs i,j where iA[j], in `3 2 1 4 5`, 3>2, 3>1 and 2>1, but we only need 1 swap to sort it. – Juan Lopes Mar 12 '13 at 15:41
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/26041/discussion-between-ivaylo-strandjev-and-juan-lopes) – Ivaylo Strandjev Mar 12 '13 at 15:41
0

Assuming:

  1. The array elements are the integers 1 to N.

Steps:

  1. Allocate a second (histogram) array H of length N.
  2. In a single pass through the initial array A, for each index i increment H[ (A[i] - i) % N]
  3. In a single pass through H, identify the element R of H with the maximum count
  4. Clear H.
  5. Identify the number of Orbits in the original array under a rotation by R. (by stepping forward through H until H[i]=0, then stepping through the orbit for which A[i] is a member under the rotation R) setting H[i]=1 for each member of the orbit, and repeating until the element H[N-1] has been processed (counting the nubmer of orbits as you go). This is also O(N) as each element of A is visited exactly once.
  6. The required number of swaps = N - Orbits.

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).

Pieter Geerkens
  • 11,775
  • 2
  • 32
  • 52
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

Above code isrecursive approach to solve the problem Complexity O(N^3)

code has been edited to print only min number of swaps.