I recently came across a Microsoft Interview Question for Software Engineer.
Given an array of positive and negative integers, re-arrange it so that you
Here is a constriant version of O(n) time O(1) space solution, it assume maxValue*(maxValue+1) is less than Integer.MAX_VALUE, where maxValue is the result of maxmum value minus minmum value in the array. It utilize the original array as the temporary array to store the result.
public static void specialSort(int[] A){
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for(int i=0; i<A.length; i++){
if(A[i] > max)
max = A[i];
if(A[i] < min)
min = A[i];
}
//Change all values to Positive
for(int i=0; i<A.length; i++)
A[i]-= min;
int newMax = max-min+1;
//Save original negative values into new positions
int currNegativeIndex = 0;
for(int i=0; i<A.length; i++)
if(A[i]%newMax < (-min))
A[currNegativeIndex++] += (A[i]%newMax)*newMax;
//Save original positive values into new positions
int currPositiveIndex = currNegativeIndex;
for(int i=0; i<A.length; i++)
if(A[i]%newMax > (-min))
A[currPositiveIndex++] += (A[i]%newMax)*newMax;
//Recover to original value
for(int i=0; i<A.length; i++){
A[i] = A[i]/newMax + min;
}
}
I very much doubt if O(n) time and O(1) is feasible with an array. Some suggest linked list, but you will need a custom linked list where you have direct access to the nodes to do this, ie. language-built-in linked lists won't work.
Here's my idea using a custom doubly linked list which satisfy the constrained complexities, using [1, 7, -5, 9, -12, 15] as an example:
Loop through the list, if see a negative, cut it off and add it to the end of the negatives at the front. Each operation is O(1) so total time is O(n). Linked list operations are in-place so O(1) space.
In detail:
last_negative_node = null;
at -5:
cut off -5 by setting 7.next = 9,
then add -5 to front by -5.next = 1,
then update last_negative_node = 5 // O(1), the linked list is now [-5, 1, 7, 9, -12, 15]
at -12:
cut off -12 by setting 9.next = 15,
then add -12 to front by -12.next = last_negative_node.next,
then update last_negative_node.next = -12,
then update last_negative_node = -12 //O(1), the linked list is now [-5, -12, 1, 7, 9, 15]
no more negatives so done.
int [] input = {1, 7, -5, 9, -12, 15};
int [] output = new int [input.length];
int negativeIdx = 0;
int positiveIdx = input.length - 1;
for(int i = 0; i < input.length ; i++) {
if(input[i] < 0) {
output [negativeIdx++] = input[i];
} else {
output [positiveIdx--] = input[i];
}
}
System.out.println
(Arrays.toString(output));
Output:
[-5, -12, 15, 9, 7, 1]
If the structure in the beginning doesn't have to be an array, it's even simpler.
If you have the original numbers in a linked list it's easy.
You can re-arrange the linked list, just each time point the negative's next to the next negative, and the positive's next to the next positive.
Again C like code, ignore syntax. (might need a null check here and there, but this is the idea)
Cell firstPositive;
Cell* lastPoisitive;
lastPoisitive = &firstPositive;
Cell firstNegative;
Cell* lastNegative;
lastNegative = &firstNegative;
Cell* iterator;
for(Iterator = list.first ; Iterator != null ; Iterator = Iterator->next) {
if (Iterator->value > 0 ) lastPoisitive->next = Iterator;
else lastPoisitive->next = Iterator;
}
list.first = firstNegative->next;
list.last.next = firstPositive->next;
First, count the number k
of negative elements.
Then, you know that the first k
numbers of the array (first part of the array) should be negative.
The following N - k
elements should be positive after sorting the array.
You maintain two counters of how many elements respect those conditions in both parts of the array and increment it at each step until you know that one part is OK (counter is equal to the size of that part). Then the other part is OK too.
This requires O(1) storage and takes O(N) time.
Implementation in C++ :
#include <iostream>
#include <vector>
using namespace std;
void swap(vector<int>& L, int i, int j) {
int tmp = L[i];
L[i] = L[j];
L[j] = tmp;
}
void signSort(vector<int>& L) {
int cntNeg = 0, i = 0, j = 0;
for (vector<int>::iterator it = L.begin(); it < L.end(); ++it) {
if (*it < 0) ++cntNeg;
}
while (i < cntNeg && cntNeg + j < L.size()) {
if (L[i] >= 0) {
swap(L, i, cntNeg + j);
++j;
} else {
++i;
}
}
}
int main(int argc, char **argv) {
vector<int> L;
L.push_back(-1);
L.push_back(1);
L.push_back(3);
L.push_back(-2);
L.push_back(2);
signSort(L);
for (vector<int>::iterator it = L.begin(); it != L.end(); ++it) {
cout << *it << endl;
}
return 0;
}
You can use 2 queues and merge them. That way, you only iterate once on the first array and once each sub queue.
negatives = []
positives = []
for elem in array:
if elem >= 0:
positives.push(elem)
else
negatives.push(elem)
result = array(negatives, positives)