Interleave array in constant space Interleave array in constant space arrays arrays

Interleave array in constant space


This is the sequence and notes I worked out with pen and paper. I think it, or a variation, will hold for any larger n.

Each line represents a different step and () signifies what is being moved this step and [] is what has been moved from last step. The array itself is used as storage and two pointers (one for L and one for N) are required to determine what to move next. L means "letter line" and N is "number line" (what is moved).

   A   B   C   D    1   2   3   4L  A   B   C  (D)   1   2   3   4  First is L, no need to move last NN  A   B   C  (3)   1   2  [D]  4L  A   B  (C)  2    1  [3]  D   4N  A   B   1  (2)  [C]  3   D   4L  A  (B)  1  [2]   C   3   D   4N  A  (1) [B]  2    C   3   D   4   A  [1]  B   2    C   3   D   4  Done, no need to move A

Note the varying "pointer jumps" - the L pointer always decrements by 1 (as it can not be eaten into faster than that), but the N pointer jumps according to if it "replaced itself" (in spot, jump down two) or if it swapped something in (no jump, so the next something can get its go!).


This problem isn't as easy as it seems, but after some thought, the algorithm to accomplish this isn't too bad. You'll notice the first and last element are already in place, so we don't need to worry about them. We will keep a left index variable which represents the first item in the first half of the array that needs changed. After that we set a right index variable to the first item in the 2nd half of the array that needs changed. Now all we do is swap the item at the right index down one-by-one until it reaches the left index item. Increment the left index by 2 and the right index by 1, and repeat until the indexes overlap or the left goes past the right index (the right index will always end on the last index of the array). We increment the left index by two every time because the item at left + 1 has already naturally fallen into place.

Pseudocode

  1. Set left index to 1
  2. Set right index to the middle (array length / 2)
  3. Swap the item at the right index with the item directly preceding it until it replaces the item at the left index
  4. Increment the left index by 2
  5. Increment the right index by 1
  6. Repeat 3 through 5 until the left index becomes greater than or equal to the right index

Interleaving algorithm in C(#)

protected void Interleave(int[] arr)  {      int left = 1;      int right = arr.Length / 2;      int temp;      while (left < right)      {          for (int i = right; i > left; i--)          {              temp = arr[i];              arr[i] = arr[i - 1];              arr[i - 1] = temp;          }          left += 2;          right += 1;      }  }    

This algorithm uses O(1) storage (with the temp variable, which could be eliminated using the addition/subtraction swap technique) I'm not very good at runtime analysis, but I believe this is still O(n) even though we're performing many swaps. Perhaps someone can further explore its runtime analysis.


First, the theory: Rearrange the elements in 'permutation cycles'. Take an element and place it at its new position, displacing the element that is currently there. Then you take that displaced element and put it in its new position. This displaces yet another element, so rinse and repeat. If the element displaced belongs to the position of the element you first started with, you have completed one cycle.

Actually, yours is a special case of the question I asked here, which was: How do you rearrange an array to any given order in O(N) time and O(1) space? In my question, the rearranged positions are described by an array of numbers, where the number at the nth position specifies the index of the element in the original array.

However, you don't have this additional array in your problem, and allocating it would take O(N) space. Fortunately, we can calculate the value of any element in this array on the fly, like this:

int rearrange_pos(int x) {    if (x % 2 == 0) return x / 2;    else return (x - 1) / 2 + n; // where n is half the size of the total array}

I won't duplicate the rearranging algorithm itself here; it can be found in the accepted answer for my question.

Edit: As Jason has pointed out, the answer I linked to still needs to allocate an array of bools, making it O(N) space. This is because a permutation can be made up of multiple cycles. I've been trying to eliminate the need for this array for your special case, but without success.. There doesn't seem to be any usable pattern. Maybe someone else can help you here.