Suppose we are given an input array of integers, how to find the longest convex subsequence that satisfies the following condition:
c[i] < (c[i-1] + c[i+1]) / 2
c[i-1]
, c[i]
and c[i+1]
are three consecutive elements in the subsequence.
For example, if input array is { 1, 2, -1, 0, 3, 8, 5 }
, the longest convex subsequence should be: { 1, -1, 0, 3, 8 }
or { 2, -1, 0, 3, 8 }
.
I tried to solve this problem using the same dynamic programming idea in "Longest Increasing Subsequence" (LIS) problem. But because each element in the subsequence depends on the previous two elements, it seems that an O(n^2) solution is impossible. Thank you for your help.
Here is O(N2 log N) algorithm (and since log N
is here only because of sorting we could reduce this to O(N2 log log N) or even to O(N2) with different sorting algorithms or more advanced priority queues):
P[]
. Elements inside each pair are ordered by their index.Y2 - Y1
. In case of equal Y2 - Y1
values they should be sorted by second index in decreasing order.L[]
of subsequence lengths for subsequences ending at indexes 0 .. N-1.P[]
(in sorted order): L[X2] = max(L[X2], L[X1] + 1)
. Where X
is index of element in the input array.L[]
. This is length of the longest convex subsequence.L[X2]
is updated we'll create a node pointing to the node pointed by entry corresponding to X1
, then point entry corresponding to X2
to this new node: BP_Head[X2] = new Node(BP_Head[X1])
.Convex property c[i] < (c[i-1] + c[i+1]) / 2
may be transformed to equivalent inequality c[i] - c[i-1] < c[i+1] - c[i]
. Which means that while processing pairs in sorted order we do not need to check convex property anymore. So the only task of step #4 is to grow the substrings.
This simplified variant of the algorithm needs O(N2) space. Space complexity may be reduced if instead of a large array P[]
we use a pre-sorted copy of input array S[]
together with priority queue. Step #4 receives elements from top of this priority queue. To keep size of this priority queue equal to N we may push element S[i+1] - S[j]
to the queue only after S[i] - S[j]
is removed (so the queue keeps only one element for each j
). Huge space consumed by forest of back-pointers is not needed if we use a known DP trick to store only one back-pointer (for each index) pointing to "middle" of the original back-pointer chain (and then repeating this algorithm recursively for two sub-arrays preceding and following this "middle" back-pointer).
And O(N3) algorithm:
This graph has O(N2) vertexes and O(N3) edges. It may be constructed in O(N3) time; and since it is a DAG, finding longest path also takes O(N3) time.
Lets call the longest convex sequence as LCS; The minimum possible length for N>1 is 2. The algo below is self explanatory.
int LCS[N];
LCS[0] = 1; LCS[1] =2 ;
for(i=2;i<N;i++)
{
LCS[i] = 2;
for(j=1;j<i;j++)
{
for(k=0;k<j;k++)
{
if(LCS[j]-1 == LCS[k] && A[j] < (A[k] + A[i])/2 )
LCS[i] = max( LCS[i], 1+LCS[j]);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With