Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counting the adjacent swaps required to convert one permutation into another

Tags:

algorithm

We're given two sequences of lowercase latin alphabet letters. They're both the same length and have the same amount of given types of letters (the first has an equal number of t's as the second and so on). We are required to find the minimum number of swaps (by "swap" we mean changing the order of two neighboring letters) required to transform the first sequence into the second. We can safely assume every two sequences CAN be transformed into each other. We could do this with brute-force, but the sequences are too long for that.

Input:
The length of the sequences (at least 2, at most 999999) and then two sequences.

Output:
An integer representing the number of swaps needed for the sequences to become the same.

Example:
{5, aaaaa, aaaaa} should output {0},
{4, abcd, acdb} should output {2}.

The first thing that came to my mind was bubblesort. We can simply bubblesort the sequence counting each swap. The problem is: a) it's O(n^2) worst-case b) I'm not convinced it would give me the smallest number for every case... Even the optimized bubblesort doesn't seem to be doing the trick. We could implement the cocktail sort which would solve the problem with turtles - but will it give me the best performance? Or maybe there's something simpler/faster?

This question can also be phrased as: How can we determine the edit distance between two strings when the only operation allowed is transposition?

like image 577
Positive Int Avatar asked Oct 17 '11 17:10

Positive Int


People also ask

How do you count number of swaps?

So to count number of swaps for an element, just count number of elements on right side which are smaller than it. Array is [8, 22, 7, 9, 31, 19, 5, 13]. So 14 swaps will be done.

What is the minimum number of adjacent swaps required to convert a string to a palindrome if not possible?

Thus, the minimum number of moves needed to make s a palindrome is 2.

How many swaps are required to swap the given array?

So 2 swaps are needed to make the array sorted in ascending order.

How do you sort an array by swapping adjacent elements?

Examples: Input : A[] = {1, 2, 5, 3, 4, 6} B[] = {0, 1, 1, 1, 0} Output : A can be sorted We can swap A[2] with A[3] and then A[3] with A[4]. Input : A[] = {2, 3, 1, 4, 5, 6} B[] = {0, 1, 1, 1, 1} Output : A can not be sorted We can not sort A by swapping elements as 1 can never be swapped with A[0]=2.


2 Answers

Regarding the minimum number of (not necessarily adjacent) swaps needed to convert a permutation into another, the metric you should use is the Cayley distance which is essentially the size of the permutation - the number of cycles.

Counting the number of cycles in a permutation is a quite trivial issue. A simple example. Suppose permutation 521634.

If you check the first position, you have 5, in the 5th you have 3 and in the 3rd you have 1, closing the first cycle. 2 is in the 2nd position, so it make a cycle itself and 4 and 6 make the last cycle (4 is in the 6th position and 6 in the 4th). If you want to convert this permutation in the identity permutation (with the minimum number of swaps), you need to reorder each cycle independently. The total number of swaps is the length of the permutation (6) minus the number of cycles (3).

Given any two permutations, the distance between them is equivalent to the distance between the composition of the first with the inverse of the second and the identity (computed as explained above). Therefore, the only thing you need to do is composing the first permutation and the inverse of the second and count the number of cycles in the result. All these operations are O(n), so you can get the minimum number of swaps in linear time.

like image 85
Borx Avatar answered Sep 29 '22 17:09

Borx


Here's a simple and efficient solution:

Let Q[ s2[i] ] = the positions character s2[i] is on in s2. Let P[i] = on what position is the character corresponding to s1[i] in the second string.

To build Q and P:

for ( int i = 0; i < s1.size(); ++i )     Q[ s2[i] ].push_back(i); // basically, Q is a vector [0 .. 25] of lists  temp[0 .. 25] = {0} for ( int i = 0; i < s1.size(); ++i )     P[i + 1] = 1 + Q[ s1[i] ][ temp[ s1[i] ]++ ]; 

Example:

    1234 s1: abcd s2: acdb Q: Q[a = 0] = {0}, Q[b = 1] = {3}, Q[c = 2] = {1}, Q[d = 3] = {2} P: P[1] = 1, P[2] = 4 (because the b in s1 is on position 4 in s2), P[3] = 2    P[4] = 3 

P has 2 inversions (4 2 and 4 3), so this is the answer.

This solution is O(n log n) because building P and Q can be done in O(n) and merge sort can count inversions in O(n log n).

like image 37
IVlad Avatar answered Sep 29 '22 16:09

IVlad