What is the fastest algorithm for circle shifting array for M positions?
For example, [3 4 5 2 3 1 4]
shift M = 2 positions should be [1 4 3 4 5 2 3
Swift 4 version for shifting array left.
func rotLeft(a: [Int], d: Int) -> [Int] {
var result = a
func reverse(start: Int, end: Int) {
var start = start
var end = end
while start < end {
result.swapAt(start, end)
start += 1
end -= 1
}
}
let lenght = a.count
reverse(start: 0, end: lenght - 1)
reverse(start: lenght - d, end: lenght - 1)
reverse(start: 0, end: lenght - d - 1)
return result
}
For example, if input array is a = [1, 2, 3, 4, 5]
, and left shift offset is d = 4
, then result will be [5, 1, 2, 3, 4]
@IsaacTurner 's answer (C) https://stackoverflow.com/a/32698823/4386969
and @SomeStrangeUser 's answer (Java): https://stackoverflow.com/a/18154984/4386969
provide a simple O(N) time, O(1) space algorithm that answers the question and requires exactly N element assignments. I believe though (and someone correct me if I'm wrong) that computing the gcd between N and M is not necessary; simply counting the number of elements that we have put in their correct place should suffice. This is because once we have put an element in its correct place, we are guaranteed that we won't have to access it again neither in the current cycle nor in subsequent ones.
Here is a Python 3 implementation with this additional simplification:
# circle shift an array to the left by M
def arrayCircleLeftShift(a, M):
N = len(a)
numAccessed = 0
cycleIdx = 0
while numAccessed != N:
idx = cycleIdx
swapIdx = (idx + M) % N
tmp = a[idx]
while swapIdx != cycleIdx:
a[idx] = a[swapIdx]
numAccessed += 1
idx = swapIdx
swapIdx = (idx + M) % N
a[idx] = tmp
numAccessed += 1
cycleIdx += 1
If you want O(n) time and no extra memory usage (since array was specified), use the algorithm from Jon Bentley's book, "Programming Pearls 2nd Edition". It swaps all the elements twice. Not as fast as using linked lists but uses less memory and is conceptually simple.
shiftArray( theArray, M ):
size = len( theArray )
assert( size > M )
reverseArray( theArray, 0, size - 1 )
reverseArray( theArray, 0, M - 1 )
reverseArray( theArray, M, size - 1 )
reverseArray( anArray, startIndex, endIndex ) reverses the order of elements from startIndex to endIndex, inclusive.
Here is my solution in Java which got me 100% Task Score and 100% Correctness at Codility:
class Solution {
public int[] solution(int[] A, int K) {
// write your code in Java SE 8
if (A.length > 0)
{
int[] arr = new int[A.length];
if (K > A.length)
K = K % A.length;
for (int i=0; i<A.length-K; i++)
arr[i+K] = A[i];
for (int j=A.length-K; j<A.length; j++)
arr[j-(A.length-K)] = A[j];
return arr;
}
else
return new int[0];
}
}
Note that despite seeing two for
loops, the iteration on the entire array is only done once.
Keep two indexes to the array, one index starts from beginning of the array to the end of array. Another index starts from the Mth position from last and loops through the last M elements any number of times. Takes O(n) at all times. No extra space required.
circleArray(Elements,M){
int size=size-of(Elements);
//first index
int i1=0;
assert(size>M)
//second index starting from mth position from the last
int i2=size-M;
//until first index reaches the end
while(i1<size-1){
//swap the elements of the array pointed by both indexes
swap(i1,i2,Elements);
//increment first pointer by 1
i1++;
//increment second pointer. if it goes out of array, come back to
//mth position from the last
if(++i2==size) i2=size-M;
}
}
In theory, the fastest one is a loop like this:
if (begin != middle && middle != end)
{
for (i = middle; ; )
{
swap(arr[begin++], arr[i++]);
if (begin == middle && i == end) { break; }
if (begin == middle) { middle = i; }
else if (i == end) { i = middle; }
}
}
In practice, you should profile it and see.