Re: how to get the longest ordered sub sequence of a list
- To: mathgroup at smc.vnet.net
- Subject: [mg103227] Re: [mg103158] how to get the longest ordered sub sequence of a list
- From: DrMajorBob <btreat1 at austin.rr.com>
- Date: Fri, 11 Sep 2009 05:25:08 -0400 (EDT)
- References: <200909090845.EAA05996@smc.vnet.net>
- Reply-to: drmajorbob at yahoo.com
The following can be modified to do what you want. It mimics
LongestIncreasingSubsequence from Combinatorica, but much faster.
Clear[zeroPad, singleLongestIncreasing]
zeroPad[{}] = {0};
zeroPad[x_List] := x
singleLongestIncreasing[x_List] :=
Module[{t = Append[x, 1 + Max[x]], len, pred, path, max},
path[i_Integer, o___Integer] /; pred[i] != {} :=
path[Last@pred@i, i, o];
len[i_] := len[i] =
Module[{mx, prior, pick, nxt = t[[i]]},
pick = Pick[Range[i - 1], Take[t, i - 1] - nxt, _?Negative];
prior = len /@ pick;
mx = Max@zeroPad@prior;
pred[nxt] = t[[Pick[pick, prior, mx]]];
1 + mx];
len /@ Range@Length@t;
Most[path@Last@t /. path -> List]
]
One way to use it for decreasing subsequences is to Reverse twice:
Reverse@singleLongestIncreasing@Reverse@originalList
However, this is a code for Integer lists, and it finds STRICTLY
increasing sublists only.
To get around that, consider an example with repeats:
s = RandomInteger[{0, 10}, 25]
s2 = Ordering@Ordering@s
Ordering@s == Ordering@s2
s[[Ordering@s2]] == Sort@s
{3, 5, 5, 6, 8, 8, 7, 10, 8, 8, 8, 0, 4, 10, 2, 7, 4, 7, 3, 10, 6, 2, \
10, 4, 3}
{4, 10, 11, 12, 17, 18, 14, 22, 19, 20, 21, 1, 7, 23, 2, 15, 8, 16, \
5, 24, 13, 3, 25, 9, 6}
True
True
The idea is that s and s2 sort the same way, but s2 is Integer with no
repeats. The same thing happens if we start with real numbers:
s = RandomReal[{0, 10}, 25]
s2 = Ordering@Ordering@s
Ordering@s == Ordering@s2
s[[Ordering@s2]] == Sort@s
{9.36262, 3.15484, 5.93621, 7.32264, 8.48407, 5.30091, 6.85566, \
3.35133, 3.01294, 9.43156, 6.48782, 0.719399, 9.77835, 9.8369, \
9.70456, 8.39239, 6.25382, 2.75411, 0.572293, 2.25703, 6.57412, \
1.02859, 6.53337, 5.17617, 7.48962}
{21, 7, 11, 17, 20, 10, 16, 8, 6, 22, 13, 2, 24, 25, 23, 19, 12, 5, \
1, 4, 15, 3, 14, 9, 18}
True
True
So... to find a non-decreasing subsequence of s, find a strictly
increasing subsequence of s2, and use the result as an index.
Back to an integer example, so that we can visually check it:
s = RandomInteger[{0, 10}, 25]
pairs = Sort@Transpose@{s2 = Ordering@Ordering@s, s}
pairs[[singleLongestIncreasing@s2]][[All, 2]]
{6, 6, 2, 3, 4, 10, 3, 8, 2, 7, 2, 0, 7, 8, 1, 8, 5, 0, 8, 1, 6, 9, \
6, 7, 9}
{{1, 0}, {2, 0}, {3, 1}, {4, 1}, {5, 2}, {6, 2}, {7, 2}, {8, 3}, {9,
3}, {10, 4}, {11, 5}, {12, 6}, {13, 6}, {14, 6}, {15, 6}, {16,
7}, {17, 7}, {18, 7}, {19, 8}, {20, 8}, {21, 8}, {22, 8}, {23,
9}, {24, 9}, {25, 10}}
{2, 3, 3, 7, 7, 8, 8, 8, 9, 9}
or, a one-liner:
Sort[s][[singleLongestIncreasing@Ordering@Ordering@s]]
{2, 3, 3, 7, 7, 8, 8, 8, 9, 9}
or, a bit faster:
s[[t = Ordering@s]][[singleLongestIncreasing@Ordering@t]]
{2, 3, 3, 7, 7, 8, 8, 8, 9, 9}
To get a strictly increasing subsequence, when there are repeats... I'm
not sure, since
Tally[%][[All, 1]]
{2, 3, 7, 8, 9}
may not be the longest such.
Bobby
On Wed, 09 Sep 2009 03:45:59 -0500, a boy <a.dozy.boy at gmail.com> wrote:
> how to get a (strict or not-strict)decreasing sub sequence of a list?
> ----------------
> increasing ?
>
--
DrMajorBob at yahoo.com
- References:
- how to get the longest ordered sub sequence of a list in
- From: a boy <a.dozy.boy@gmail.com>
- how to get the longest ordered sub sequence of a list in