This can be done in O(N)
time and O(N)
extra memory space with the help of two stacks (one for indices and other for values).
I'll explain the algorithm with the help of your example.
Input 12 15 22 9 7 2 18 23 27
Initialize Output Array O[] as all -1.
1. Start from the first element. Set CurrentElement = A[0] (12). index = 0
2. Push A[index] in a Stack S_values. Push index in a Stack S_indices.
3. Increment index.
4. while ( S_values is not empty && A[index] is > than S_values.top() )
- Set output_index = S_indices.top()
- set O[output_index] = A[index].
- S_values.pop()
- S_indices.pop().
5. If index < length(Input)-1 Goto Step 2.
6. Set O[index] = -1. // Last element.
This works because the top of the stack S_values
shall always have the lowest value and the elements shall be popped out from it in ascending order. Similarly the stack S_indices
shall always have the largest value on top and indices shall be popped out in descending order.
EDIT: Code in C++
#include <vector>
#include <stack>
#include <iostream>
using std::cout;
using std::endl;
using std::vector;
using std::stack;
int main()
{
vector<int> Input = { 12, 15, 22, 9, 7, 2, 18, 23, 27};
vector<int> Output( Input.size(), -1 );
stack<int> S_values, S_indices;
S_values.push( Input[0] );
S_indices.push( 0 );
for ( size_t index = 1; index < Input.size(); ++index )
{
while ( !S_values.empty() && Input[index] > S_values.top() )
{
size_t output_index = S_indices.top();
Output[ output_index ] = Input[ index ];
S_values.pop();
S_indices.pop();
}
S_values.push( Input[index] );
S_indices.push( index );
}
for ( auto &x : Output )
cout << x << " ";
cout << endl;
return 0;
}
Output:
15 22 23 18 18 18 23 27 -1