10

Given two arrays, how do you check if one is a cyclic permutation of the other?

For example, given a = [1, 2, 3, 1, 5], b = [3, 1, 5, 1, 2], and c = [2, 1, 3, 1, 5] we have that a and b are cyclic permutations but c is not a cyclic permutation of either.

Note: the arrays may have duplicate elements.

dsg
  • 12,924
  • 21
  • 67
  • 111
  • possible duplicate of [Interview question: Check if one string is a rotation of other string.](http://stackoverflow.com/questions/2553522/interview-question-check-if-one-string-is-a-rotation-of-other-string) –  May 24 '11 at 02:51
  • 1
    @Aryabhatta -- Yes, it is a duplicate. Thanks for pointing that out. – dsg May 24 '11 at 03:46

4 Answers4

23

The standard trick here is to concatenate one of the arrays with itself, and then try to find the 2nd array in the concatenated array.

For example, 'a' concatenated with itself is:

[1, 2, 3, 1, 5, 1, 2, 3, 1, 5]

Since you do see 'b' in this array starting from the 3rd element then a and b are cyclic permutations.

Himadri Choudhury
  • 10,217
  • 6
  • 39
  • 47
  • I assume you're presupposing the arrays are of equal lengths. Even so, why is it not possible for there to be false positives? – dsg May 24 '11 at 02:26
  • 4
    Yes. If the arrays are not of equal lengths then they are trivially not permutations of each other. – Himadri Choudhury May 24 '11 at 02:28
  • 1
    If the algorithm says it is a permutation, it will be by construction. If you do find 'b' in 'a' +'a' at position ai, then if you shift 'a' by i so that ai is the first element of 'a' the wrap around will be exactly the part in the 2nd 'a' of the concatenated array that you matched against. – Himadri Choudhury May 24 '11 at 02:33
  • 2
    That's the proof. The algorithm tell you exactly how much to shift 'a' to get 'b' if they are cyclic permutations of each other. – Himadri Choudhury May 24 '11 at 02:39
8

If A and B are cyclic permutations of each other, A will be found in doubled list BB (as will B in AA).

Amadan
  • 191,408
  • 23
  • 240
  • 301
8

The efficient way to handle large amounts of data, is to transform each of them into a 'canonical' form then compare to see of they're equal. For this problem you can choose as the canonical form of all the rotated permutations the one that 'sorts smallest'.

So the canonical form for 'a' and 'b' is [1, 2, 3, 1, 5] which are equal so they are acyclic permutations.

The canonical form for 'c' is [1, 3, 1, 5, 2] which is different.

karmakaze
  • 34,689
  • 1
  • 30
  • 32
  • I like this algorithm. It is intuitive why it works. Can you explain how to find the canonical form when there are duplicate elements (e.g. the `1` in `a` and `b`)? – dsg May 24 '11 at 02:37
  • 1
    Consider the entries to be like letters and the permutations to be like words. The 'word' 12315 sorts before 15123 so it's the smallest, i.e. canonical one. – karmakaze May 25 '11 at 14:49
  • I see. So finding the canonical representation takes `O(n^2)` element-wise comparisons where `n` is the length of the array? That is: loop through all `n` possible rotations keeping the current minimum, and for each rotation, perform `O(n)` comparisons to determine whether to update the minimum. Maybe there's a better way.. – dsg May 26 '11 at 05:03
  • @dsg Consider the number of comparisons if you have n arrays to compare, as in 'large amounts of data'. – karmakaze May 26 '11 at 15:08
  • In case, that's still not clear enough for you. Having a canonical form means that you can hash the values to speed up comparisons. – karmakaze May 26 '11 at 15:15
  • Love it! I came up with exactly this representation for my problem. – mxxk Nov 21 '15 at 23:44
-1

Here is simple adhoc approach to findout cyclic permutations with O(n) time complexity.

a = [1, 2, 3, 1, 5], b = [3, 1, 5, 1, 2]

Find index of b[0] in a[], lets say index is 'x'.Then start navigating in both the array's. a[] starts from index 'x' and b[] starts from '0'. Such that both of them must have same values. If not, they are not cyclic. Here is the sample code.

 public class CyclicPermutation {

    static char[] arr = { 'A', 'B', 'C', 'D' };
    static char[] brr = { 'C', 'D', 'K', 'B' };
    boolean dec = false;

    public static void main(String[] args) {
        boolean avail = true;
        int val = getFirstElementIndex(brr[0]);
        if(val ==Integer.MIN_VALUE){
            avail = false; 
            return;
            }

        for (int i = val, j = 0; j <= brr.length-1; ) {
            if (i > arr.length-1) {
                i = 0;
            }
            if (arr[i] == brr[j]) {
                i++;

                j++;

            } else {
                avail = false;
                System.out.println(avail);
                return;
            }


        }

   System.out.println(avail);
    }

    public static int getFirstElementIndex(char c) {

        for (int i = 0; i <= arr.length; i++) {
            if (arr[i] == c) {
                return i;
            }
        }
        return Integer.MIN_VALUE;
    }


}
Anvesh_vs
  • 376
  • 4
  • 7