mindstalk: (Default)
mindstalk ([personal profile] mindstalk) wrote2017-01-28 01:17 pm

fast array rotation

A simple problem I'd never had occasion to think much before, before I saw a sample coding problem.

How to rotate the elements of an N-element array by k spaces? An obvious way is to shuffle it one space, k times, but that's slow, O(N*k). Faster, which I saw about as soon as I thought about performance, is to use a second array B, where B[(i+k)%N] = A[i]. But that takes O(N) extra space. Can you do better?

Yes, as I realized at 5am. For each element A[i], move it to A[(i+k)%N]. O(N) time, O(1) extra space. Can't beat that!

Except some mildly tricky math intervenes: the natural approach only works if N and k are relatively prime. A more general solution is

let g = gcd(N,k)
for i in [0,g)
  for j in [0, N/g)
    shuffle element k spaces


Despite looking like a double loop, it's still O(N), with g*N/g iterations.

[2020 Edit: Looking back... I find this less than clear. I went to the code to make sure I got it right.

#ar = (array)
g = gcd(N, k)
for i in range(g):
    cur = ar[i]
    for j in range(1, N//g+1):
        temp = ar[(i + j*k) % N]
        ar[(i + j*k) % N] = cur
        cur = temp

]

I've also learned that C++ has a gcd function now. std::experimental::gcd, in the header experimental/numeric. C++17 moves it out of experimental but even g++ isn't doing that by default.

The really annoying this is that this is the sort of solution that comes naturally to me lying in bed, with little conscious effort, but that I'd likely fail to get in a whiteboard session or timed coding test, due to stress dropping my working IQ.
mtbc: photograph of me (Default)

[personal profile] mtbc 2017-01-29 08:31 pm (UTC)(link)
I don't think I would have thought my way to your solution. Cool, thank you for sharing.

[personal profile] thomasyan 2017-02-01 02:26 am (UTC)(link)
I think this is sometimes called the dolphin solution because of the way you sort of jump around, and that it does not have great locality.

Other solutions involve reversing contiguous chunks of the array, and maybe have better performance in practice.