Googles appar
Huvudmeny

Post a Comment On: cbloom rants

"09-28-11 - Algorithm - Next Index with Lower Value"

5 Comments -

1 – 5 of 5
Blogger b0b0b0b said...

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.

October 4, 2011 at 12:26 PM

Blogger cbloom said...

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

October 4, 2011 at 12:58 PM

Blogger cbloom said...

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.

October 4, 2011 at 1:00 PM

Blogger Unknown said...

Thanks for all your posts, they've been very helpful. I implemented this algorithm, and discovered that it was incomplete. I'm sure you handled this in your local implementation years ago, but I wanted to document it for others who find this helpful as well.

The problem happens when the stack is not empty at the end of the loop. In this case, the stack holds all the values "i" that don't yet have any "j" such that "j > i && A[j] < A[i]". There are no more "j" values to consider, so this condition will never become true.

In your notation, "B[i] = j", so we want the invariant on exit to be that "B[i] > i && A[B[i]] < A[i]".

Since the stack is stored in the B[] array in the order encountered, and since i increments, these entries for B[i] do satisfy "B[i] > i". The fact that they are still on the stack means "!(B[i] > i && A[B[i]] < A[i])". Since "B[i] > i", this proves "A[B[i]] >= A[i]". If the "A[i]" array has no duplicates, as in the suffix array use case, this becomes a strict inequality: "A[B[i]] > A[i]".

Again, in the suffix array case, this means the array that was supposed to only hold pointers to longest *past* matches also has some pointers to *future* matches.

There are two fixes I can think of. The most obvious is, after exiting the loop, just pop the stack until it is empty, setting B[i] to "none" as you go.

Another solution is to have a sentinel token A[end] at the end of the list that satisfies A[end] < A[i] for all i != end. If "end" is the same as "none", these two solutions are effectively equivalent. The first solution is more obvious, the second solution uses less code and avoids special case handling.

June 16, 2016 at 9:28 AM

Blogger cbloom said...

Yep, you're totally right, I failed to mention that.

Both your solutions are good.

Lots of stuff in suffix trees & suffix arrays works neatly if you have a sentinel token at the end, unfortunately we don't get a byte that's > 255 ;) So in practice the code gets a lot uglier with lots of special case handling for the end-of-string case that would've been handled very neatly with a sentinel.

I use the first option of manually bubbling back a null entry at the end. It's in the String Match Test code that I released, in MakeNextLowerPosArray.

June 16, 2016 at 10:20 AM

You can use some HTML tags, such as <b>, <i>, <a>

This blog does not allow anonymous comments.

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.