Monday, February 3, 2014

Circular right shift by n

Problem:
Given an integer array. Perform circular right shift by n.
Give the best solution.

Solution:

O(n)/O(1):

void reverse(int A[], int start, int end)
{
 while(start < end)
  swap(A[start++], A[end--]);
}

//shift A[0…sz-1] by n (n>0)
void shiftArray(int A[], int sz, int n)
{
 n = n%sz;
 reverse(A, 0, sz-1);
 reverse(A, 0, n-1);
 reverse(A, n, sz-1);
 return;
}

But the above solution performs too many swaps. There's an alternative O(n)/O(1) solution that swaps each element only once. We start with the first element at index 0 and put it to its final position (at index [n % length]). The former element at index [0 + n % length] will now be saved in a temporary variable. Now, on the next loop iteration we put the temporary element to its final position (at index [(n + n) % length]) and similarly store the element from that new position to a temporary variable. We continue the process until we put an element at index 0, after which the array is rotated. As an example, consider the following example with an array of 5 elements that needs to be shifted by 3:

1 2 3 4 5

Shift it by 3:

x 2 3 1 5 - 4
x 4 3 1 5 - 2
x 4 3 1 2 - 5
x 4 5 1 2 - 3
3 4 5 1 2

Each line above represents the state of the array on each iteration of the loop. A number after the '-' sign is the temporary storage used for an element currently being shifted. The 'x' represents a position that doesn't contain a valid data and needs to be filled last. So, the loop would look like this:

int i = 0;
int temp = array[0];
do {
   int k = i + n % length;
   int t = array[k];
   array[k] = temp;
   temp = t;
   i = (i + n) % length;
} while (i != 0);
// Finally, fill the index 0:
array[0] = temp;

Complexity:
time - O(n)
space - O(1)
Links and credits:
http://www.careercup.com/question?id=6282862240202752

No comments:

Post a Comment