Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rotating an array

Tags:

java

algorithm

I'm trying to rotate an array such that given a number and an array, rotate the array by that amount. IE:

abcdefgh

given 3:

fghabcde

What is the best way to do this without using additional data structures/minimal space?

Here is a function header:

public static char[] rotateString(char[] s, int rotateAmount){

}
like image 545
KWJ2104 Avatar asked Dec 28 '22 06:12

KWJ2104


2 Answers

The Java implementation of Collections.rotate(List, int) can be found here; it uses only constant overhead, and it's quite clean and easy to understand. I wouldn't necessarily just call it (although with a wrapper like Guava's Chars.asList, there would only be a constant overhead), but the algorithm is neat and clean, and you could adapt it easily enough to your needs.

It's O(n), but the reason why isn't quite obvious; most of the work is figuring out why it will never visit any one index more than once. I'll leave that as an exercise.

like image 40
Louis Wasserman Avatar answered Jan 16 '23 16:01

Louis Wasserman


Firstly, I will make a big assumption that "better" means "I do not want any/as few new data structures".

If this is the case, then the simplest solution is the best, since I don't need to bother optimising by time. I know that the other solutions are much more elegant, I've only posted it because I've read the question as "make sure it's minimal space-wise".

private static String rotate( final char[] a, final int n ) {
    for(int i = 0; i < n; i++) {
        char tmp = a[a.length-1];
        for(int j = a.length-1; j >= 0; j--) {
            a[j] = j == 0 ? tmp : a[(j-1+a.length)%a.length];
        }
    }
    return new String(a);
}

So I hacked this out pretty quickly. Basically, I'm just doing rotates by lengths of one until I've rotated n number of times. To optimise it you probably could take gcd(n, a.length).

Now, since my solution is pretty terrible, I'll also post the following code taken from here

void reverse_string(char* str, int left, int right) {
  char* p1 = str + left;
  char* p2 = str + right;
  while (p1 < p2) {
    char temp = *p1;
    *p1 = *p2;
    *p2 = temp;
    p1++;
    p2--;
  }
}

void rotate(char* str, int k) {
  int n = strlen(str);
  reverse_string(str, 0, n-1);
  reverse_string(str, 0, k-1);
  reverse_string(str, k, n-1);
}

This is, what I assume to be a C-style implementation that runs faster than mine, using a basic idea that with three reverses, you can implement an inline shift.

As is said here,

The trick is to do three reverse operation. One for the entire string, one from index 0 to k-1, and lastly index k to n-1. Magically, this will yield the correct rotated array, without any extra space! (Of course, you need a temporary variable for swapping).

I haven't verified this property on the blog I've linked to, so I will post it with a grain of salt that it would appear to work but I've never tested it myself...

like image 144
blahman Avatar answered Jan 16 '23 15:01

blahman