For each i, find the next entry j (j > i) such that the value is lower (A[j] < A[i]).
Fill out B[i] = j for all i.
For array size N this can be done in O(N).
Here's how :
I'll call this algorithm "stack of fences". Walk the array A[] from start to finish in one pass.
At i, if the next entry (A[i+1]) is lower than the current (A[i]) then you have the ordering you want immediately and you just assign B[i] = i+1.
If not, then you have a "fence", a value A[i] which is seeking a lower value. You don't go looking for it immediately, instead you just set the current fence_value to A[i] and move on via i++.
At each position you visit when you have a fence, you check if the current A[i] < fence_value ? If so, you set B[fence_pos] = i ; you have found the successor to that fence.
If you have a fence and find another value which needs to be a fence (because it's lower than its successor) you push the previous fence on a stack, and set the current one as the active fence. Then when you find a value that satisfies the new fence, you pop off the fence stack and also check that fence to see if it was satisfied as well. This stack can be stored in place in the B[] array, because the B[] is not yet filled out for positions that are fences.
The pseudocode is :
fence_val = fence_pos = none
for(int i=1;i
<size;i++)
{
int prev = A[i-1];
int cur = A[i];
if ( cur > prev )
{
// make new fence and push stack
B[i_prev] = fence_pos;
fence_pos = i_prev;
fence_val = prev;
}
else
{
// descending, cur is good :
B[i_prev] = i;
while( cur < fence_val )
{
prev_fence = B[fence_pos];
B[fence_pos] = i;
fence_pos = prev_fence;
if ( fence_pos == -1 )
{
fence_val = -1;
break;
}
fence_val = A[fence_pos];
}
}
}
This is useful in string matching, as we will see forthwith.
3 comments:
I'm not sure this is O(N). What if the input is an array starting with even integers from 2..M and ending with odd integers from 1..M-1.
It's pretty trivial to prove.
Every iteration writes to B[i] at least once
each B[i] can written to at most twice (once for a fence and once for its final correct value)
there are N elements of B[]
therefore # of operations is >= N and <= 2N
QED
The full 2N time is taken by
2,4,6,8..M,M-1,M-3,M-5,...1
I wish I could find the version of this algorithm that works for windowed ranges, not just monotonic conditions.
Post a Comment