KWJ2104
KWJ2104

Reputation: 2009

Rotating an array

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){

}

Upvotes: 4

Views: 8437

Answers (8)

plucury
plucury

Reputation: 1120

Try this :

public static char[] rotateString(char[] s, int rotateAmount){
    String oldStr=new String(s);
    String newStr=oldStr.substring(oldStr.length()-rotateAmount,oldStr.length())+oldStr.substring(0,oldStr.length()-rotateAmount);
    return newStr.toCharArray();
}

Upvotes: -1

FastForward
FastForward

Reputation: 1

I think this is simplier and definitely faster

private static String rotate( char[] arrayStr, int K, int N ) {
    int[] my_array = new int[N];
    for(int item = 0; item < N; item++) {
        my_array[(item+K) % N] = arrayStr[item];
    }
    return my_array 
}

where K = number of rotation and N = lenght of array

Upvotes: 0

NNP
NNP

Reputation: 3451

Here is c# version of it just for reference (you may refer to:http://codingworkout.blogspot.com/2014/07/rotating-array.html for more details):

void swap<T>(ref T x, ref T y)
        {
            T t = x;
            x = y;
            y = t;
        }
        void Reverse(int[] a, int start, int end)
        {
            int i = start, j = end;
            while (i < j)
            {
                swap<int>(ref a[i], ref a[j]);
                i++;
                j--;
            }
        }
        void Rotate(int[] a, int k)
        {
            a.ThrowIfNull("array");
            k.Throw("k", e => e < 0);
            if (a.Length <= 1)
            {
                return;
            }
            k = k % a.Length;
            this.Reverse(a, 0, a.Length - 1);
            this.Reverse(a, 0, k - 1);
            this.Reverse(a, k, a.Length - 1);
        }

Unit Tests

[TestMethod]
        public void RotateTests()
        {
            int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
            for (int i = 1; i <= a.Length; i++)
            {
                int k = a.Length - i + 1;
                int[] b = new int[a.Length];
                this.Rotate(a, i);
                for(int j = 0;j<b.Length;j++)
                {
                    if(k > a.Length)
                    {
                        k = (k % a.Length);
                    }
                    b[j] = k;
                    k++;
                }
                for (int j = 0; j < a.Length;j++ )
                {
                    Assert.IsTrue(a[j] == b[j]);
                }
                this.Rotate(a, a.Length - i);
            }
        }

Upvotes: 0

Gangnus
Gangnus

Reputation: 24484

  1. As you have to return a result array, you have to create it anyway.
  2. The function should work in both directions and when there is one or more turnarounds - as turning by number more than the length of the array.

    public static char[] rotateString(char[] s, int rotateAmount){
        int n=s.length;
        char[] res=new char[n];
        if (n==0) return res;
    
        int turns=rotateAmount / n;
        int j=((-turns+1)*n+rotateAmount) % n;
        for (int i=0; i<n; i++){
            if(j==n) j=0;
            res[j]=s[i];
            j++;
        }
        return res;
    }
    

tested by:

    System.out.println("'',+1->"+new String(rotateString("".toCharArray(),+1)));
    System.out.println("123,+1->"+new String(rotateString("123".toCharArray(),+1)));
    System.out.println("123,-1->"+new String(rotateString("123".toCharArray(),-1)));
    System.out.println("123,-5->"+new String(rotateString("123".toCharArray(),-5)));
    System.out.println("123,-6->"+new String(rotateString("123".toCharArray(),-6)));
    System.out.println("123,+6->"+new String(rotateString("123".toCharArray(),+6)));

Upvotes: 1

user1071136
user1071136

Reputation: 15725

Something like this ? It requires O(1) extra storage for temp. Try running this with shift=1, to see the idea behind it.

public static String rotateString(char[] s, int rotateAmount) {
  int length = s.length;
  int shift = (length - rotateAmount) % length;
  for (int start = 0; start < gcd(length, shift); start++) {
    char temp = s[start];
    for (int i = (start + shift)%length; i != start; i = (i + shift) % length) {
      s[(length + i - shift) % length] = s[i];
    }
    s[(length + start - shift) % length] = temp;
  }
  return new String(s);
}

gcd(a,b) is the greatest common denominator of a and b, and can be computed using e.g., Euclid's Algorithm.

The time complexity is O(n), where n is the length of the array.

Upvotes: 1

Louis Wasserman
Louis Wasserman

Reputation: 198491

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.

Upvotes: 3

Sandeep
Sandeep

Reputation: 7334

How about using Stack?

Let me explain. When you push abcdefgh to stack it becomes hgfedcba

Now Pop one element at a time and prepend the string. lets assume rotation amount is 3.

When you pop first elemnt you get h. Since 3 is less than number of characters popped pop one more element and prepend to h. So when you pop the next element you get g. Prepend g to h. So it becomes hg. Repeat the process for the amount of rotation(here it is 3) hence it becomes fgh.

Now Create a new string and pop the rest of elements from the stack and prepend each character popped. Hence it becomes "abcd".

Combine the two strings. which is fghabcd.

Upvotes: 0

blahman
blahman

Reputation: 1314

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...

Upvotes: 6

Related Questions