Search code examples
algorithmsortingswap

How to sort an array by only being able to swap an element with another element two positions ahead (i+2)?


I have an array of integers that I need to sort. However, the only operation allowed is to swap an element at index i with the element at index i+2. This means traditional sorting algorithms like quicksort or mergesort won’t work directly because they rely on adjacent swaps.

the constraints are these:

  • the array is of lenght N
  • each integer in the array goes from 0 to N-1 (an array of size 5 would look something like this: [0,1,3,4,2]
  • the algorithm shall work also for arrays that could be composed of 100,000 cells

How can I fully sort the array given the i and i+2 swap constraint? Are there any existing algorithms or strategies that I can adapt to handle this specific problem? Also, how can I count the exact number of swaps required to sort the array completely?

Here's what I came up with so far

#include <iostream>
#include <algorithm>

using namespace std;

// Function to perform bubble sort on a static array and count swaps
int bubble_sort_with_swap_count(int arr[], int n) {
    int swap_count = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr[j], arr[j + 1]);
                swap_count++;
            }
        }
    }
    return swap_count;
}

// Function to sort the array with the given constraints and count steps
void sort_special_with_steps(int arr[], int n, int &total_swaps) {
    // Separate even and odd indexed elements
    int even_elements[n / 2 + 1], odd_elements[n / 2 + 1];
    int even_idx = 0, odd_idx = 0;
    
    for (int i = 0; i < n; i += 2) {
        even_elements[even_idx++] = arr[i];
    }
    for (int i = 1; i < n; i += 2) {
        odd_elements[odd_idx++] = arr[i];
    }
    
    // Sort both subsequences and count swaps
    int even_swaps = bubble_sort_with_swap_count(even_elements, even_idx);
    int odd_swaps = bubble_sort_with_swap_count(odd_elements, odd_idx);
    
    // Merge the sorted subsequences back into the original array
    even_idx = 0;
    odd_idx = 0;
    
    for (int i = 0; i < n; i++) {
        if (i % 2 == 0) {
            arr[i] = even_elements[even_idx++];
        } else {
            arr[i] = odd_elements[odd_idx++];
        }
    }
    
    total_swaps = even_swaps + odd_swaps;
}

int main() {
    int arr[] = {4, 1, 3, 2, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    int total_swaps = 0;
    
    sort_special_with_steps(arr, n, total_swaps);
    
    cout << "Sorted array: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    cout << "Number of steps: " << total_swaps << endl;
    
    return 0;
}

this is not nearly fast enough, I saw online that there's some sort of tree structure that can be used but I never got it to work.

here are some test cases with each their expected outputs:

  • N = 5, arr = {2,0,4,3,1] -> total_swaps = -1 (cannot be solved)
  • N = 6, arr = {2,3,0,5,4,1} -> total_swaps = 3 (can be solved)
  • N = 200, arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,115,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,86,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199}, total_swaps = -1 (cannot be solved)

Solution

  • in the end, I managed to solve it thanks to your suggestions, here's my final O(N log N) solution:

    #include <vector>
    #include <algorithm>
    using namespace std;
    // Function to merge two halves and count inversions
    int mergeAndCount(std::vector<int> &arr, int left, int mid, int right)
    {
      std::vector<int> leftSub(arr.begin() + left, arr.begin() + mid + 1);
      std::vector<int> rightSub(arr.begin() + mid + 1, arr.begin() + right + 1);
    
      int i = 0, j = 0, k = left, swaps = 0;
      while (i < leftSub.size() && j < rightSub.size())
      {
        if (leftSub[i] <= rightSub[j])
        {
          arr[k++] = leftSub[i++];
        }
        else
        {
          arr[k++] = rightSub[j++];
          swaps += leftSub.size() - i;
        }
      }
    
      while (i < leftSub.size())
      {
        arr[k++] = leftSub[i++];
      }
    
      while (j < rightSub.size())
      {
        arr[k++] = rightSub[j++];
      }
    
      return swaps;
    }
    
    // Function to implement merge sort and count inversions
    int mergeSortAndCount(std::vector<int> &arr, int left, int right)
    {
      int swaps = 0;
      if (left < right)
      {
        int mid = left + (right - left) / 2;
    
        swaps += mergeSortAndCount(arr, left, mid);
        swaps += mergeSortAndCount(arr, mid + 1, right);
        swaps += mergeAndCount(arr, left, mid, right);
      }
      return swaps;
    }
    
    // Function to count inversions
    int countInversions(std::vector<int> &arr)
    {
      return mergeSortAndCount(arr, 0, arr.size() - 1);
    }
    
    long long flip_sort(int N, int V[])
    {
      long long swaps = 0;
      vector<int> V_even;
      vector<int> V_odd;
      for (int i = 0; i < N; i++)
      {
        if (i % 2 == 0)
          if (V[i] % 2 != 0)
          {
            sort(V, V + N);
            return -1;
          }
          else
          {
            V_even.push_back(V[i]);
          }
        else if (V[i] % 2 == 0)
        {
          sort(V, V + N);
          return -1;
        }
        else
        {
          V_odd.push_back(V[i]);
        }
      }
      sort(V, V + N);
      swaps = countInversions(V_even) + countInversions(V_odd);
      return swaps;
    };