Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Longest convex subsequence in an array

Tags:

algorithm

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.

like image 749
user3116259 Avatar asked Dec 18 '13 17:12

user3116259


2 Answers

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):

  1. Create an array for each pair of input array elements: P[]. Elements inside each pair are ordered by their index.
  2. Sort these pairs according to value difference Y2 - Y1. In case of equal Y2 - Y1 values they should be sorted by second index in decreasing order.
  3. Zero-initialize array L[] of subsequence lengths for subsequences ending at indexes 0 .. N-1.
  4. For each pair from P[] (in sorted order): L[X2] = max(L[X2], L[X1] + 1). Where X is index of element in the input array.
  5. Find largest value in L[]. This is length of the longest convex subsequence.
  6. To be able to reconstruct subsequence itself, step #4 should also update chain of back-pointers. When 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:

  1. Construct graph where each vertex corresponds to (ordered by index) pair of array elements.
  2. Connect vertexes with an edge if they have one common array element which is located between remaining two elements associated with these vertexes and all three elements satisfy convex property. This edge should be directed to the vertex with larger indexes.
  3. Add source and destination nodes and connect them to every vertex.
  4. Find longest path in this graph.

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.

like image 188
Evgeny Kluev Avatar answered Nov 07 '22 18:11

Evgeny Kluev


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]);
       }
   }
}
like image 34
satyajanga Avatar answered Nov 07 '22 18:11

satyajanga