Given an input sequence, what is the best way to find the longest (not necessarily continuous) increasing subsequence
[0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15] # input
[1, 9, 13, 15] # an example of an increasing subsequence (not the longest)
[0, 2, 6, 9, 13, 15] # longest increasing subsequence (not a unique answer)
[0, 2, 6, 9, 11, 15] # another possible solution
I’m looking for the best algorithm. If there is code, Python would be nice, but anything is alright.
I just stumbled in this problem, and came up with this Python 3 implementation:
Since it took me some time to understand how the algorithm works I was a little verbose with comments, and I’ll also add a quick explanation:
seqis the input sequence.Lis a number: it gets updated while looping over the sequence and it marks the length of longest incresing subsequence found up to that moment.Mis a list.M[j-1]will point to an index ofseqthat holds the smallest value that could be used (at the end) to build an increasing subsequence of lengthj.Pis a list.P[i]will point toM[j], whereiis the index ofseq. In a few words, it tells which is the previous element of the subsequence.Pis used to build the result at the end.How the algorithm works:
i.jthat letseq[M[j]be<thanseq[i].P,MandL.Note: The only differences with the wikipedia algorithm are the offset of 1 in the
Mlist, and thatXis here calledseq. I also test it with a slightly improved unit test version of the one showed in Eric Gustavson answer and it passed all tests.Example:
At the end we’ll have:
As you’ll see
Pis pretty straightforward. We have to look at it from the end, so it tells that before60there’s40,before80there’s40, before40there’s20, before50there’s20and before20there’s10, stop.The complicated part is on
M. At the beginningMwas[0, None, None, ...]since the last element of the subsequence of length 1 (hence position 0 inM) was at the index 0:30.At this point we’ll start looping on
seqand look at10, since10is<than30,Mwill be updated:So now
Mlooks like:[1, None, None, ...]. This is a good thing, because10have more chanches to create a longer increasing subsequence. (The new 1 is the index of 10)Now it’s the turn of
20. With10and20we have subsequence of length 2 (index 1 inM), soMwill be:[1, 2, None, ...]. (The new 2 is the index of 20)Now it’s the turn of
50.50will not be part of any subsequence so nothing changes.Now it’s the turn of
40. With10,20and40we have a sub of length 3 (index 2 inM, soMwill be:[1, 2, 4, None, ...]. (The new 4 is the index of 40)And so on…
For a complete walk through the code you can copy and paste it here 🙂