Longest convex subsequence in an array

匿名 (未验证) 提交于 2019-12-03 03:06:01

问题:

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.

回答1:

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.



回答2:

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]);        }    } } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!