A linear-time algorithm that rearrange negative and positive integers with zeroes in between

Problem:

  • Array has positive, negative, and 0 integers, and values are not necessarily unique.
  • The positive values are to the right of zeroes, and the negative values are to the left of zeroes. The positive and the negative values do not have to be sorted. However, the zeros must be in between the positive and negative integers.
  • The algorithm must run in linear time.

Some acceptable answers I can think of are the following:

  • [-3, -1, -9, 0, 5, 2, 9]
  • [-5, -2, 0, 0, 5, 2, 9]
  • [-3, 0, 0, 0, 4, 1]

My thought process and attempts:

The process is very similar to the quicksort algorithm where we can choose 0 to be our pivot point. Ideally, this shouldn’t be an issue because we can simply search for the index of 0 and set that index as our pivot point to replace at the end. However, from what I understand the search process itself requires at least O(nLog(n)) run time (such as binary search), and therefore cannot be used in this case.

One extreme solution to this that I can think of that runs in a linear time is using the linear select algorithm where we split the array into subgroups of 5 and find the median of the medians of the subgroups. However, I doubt this will work since the median isn’t always going to be 0, therefore the pivot point isn’t always guaranteed to be 0.

What’s really throwing me off in the problem is that the negative and positive integers do not have to be sorted but simultaneously must be partitioned by zeroes.

What I have so far:

I was able to modify the partitioning process of the quick sort algorithm. The following runs in a linear time, but the problem is that it is not able to place the zeroes in the appropriate positions.

This is the output that I am able to get with the current progress I have:

void partition(T a[], int lo, int n) {
    size_t i = lo, j;
    for (j = i; j < n; j++){
        if (a[j] < 0){
          std::swap(a[i], a[j]);
          i++;
        }
    }
}

Using array of [9, -3, -6, 1, 3,4,-22,0]
Output of the code is [ -3 -6 -22 1 3 4 9 0 ]

Thank you very much in advance for any feedback that you may have.

>Solution :

A simple linear algorithm in two iterations can be to first push all negative numbers to the left, and in a second iteration push all positives numbers to the right.

void rearrange(T a[], int n) {
  int next_to_place= 0;
  for (int i = 0; i < n; i++) {
    if (a[i] < 0) {
      std::swap(a[i], a[next_to_place++]);
    }
  }
  for (int i = next_to_place; i < n; i++) {
    if (a[i] == 0) {
      std::swap(a[i], a[next_to_place++]);
    }
  }
}

This is suboptimal, as you can probably solve it with a single iteration (which will be more cache friendly), but it is linear and simple to understand.

Leave a Reply