每个元素的最长增加子序列

时间:2012-04-13 16:42:30

标签: algorithm

给定一个列表{x_i},我想从每个元素开始找到longest increasing subsequence,以便起始元素包含在子序列中。

显而易见的方法是在每个元素上执行通常最长的增加子序列算法,给出O(n ^ 2 logn)。这可以被打败吗?

3 个答案:

答案 0 :(得分:2)

您可以使用DP并将其降低到O(n ^ 2)。

让输入为x1,x2,...,xn

设f1,f2,...,fn是从第i个元素开始的最长增加序列的长度。将所有这些内容初始化为1。

现在,

for i = n-1, n-2, .... , 1:
    for j = i,i+1,...,n:
        if x[i]<x[j]:
            fi=max(fi, fj+1)

如果除了长度之外还需要实际序列,请跟踪另一个变量g1,g2,...,gn,其中gi是下一个要遵循的元素。将gis初始化为NULL。

for i = n-1, n-2, .... , 1:
    for j = i,i+1,...,n:
        if x[i]<x[j]:
            if fi<fj+1:
                fi=fj+1
                gi=j

一旦你有了gs,我将让你弄清楚如何从特定位置开始枚举序列。

答案 1 :(得分:1)

更高效的算法将依赖于每次迭代共享相同的数据结构,而不是每次都重新启动算法。一种方法是找到输入列表反向的最长递减子序列。这应该为您提供一个数据结构,使您可以对每个元素的前任进行持续访问,以及从该元素开始的子序列的长度。

对于每个起始元素:如果它处于最长的递减子序列中,请按照其前导到最后。如果不是,找到更大和更右边的元素,并拥有最多的前辈,并遵循该元素的前辈。

这将给出O(N ^ 2)的最坏情况时间复杂度,但至少还需要输出结果。

答案 2 :(得分:0)

int main(){

int arr[]={1,10,5,12,17,18,19};
int t[]={1,0,0,0,0,0,0};
int i,j;
vector<int>v[7];
v[0].push_back(1);       
for(i =1;i<7;i++){

    for(j =0;j<i;j++){
          if(arr[j]<arr[i]){

             if(t[j]>=t[i]){
                 t[i]=t[j]+1;
                 v[i].push_back(arr[j]);
             }
          }
     }
     if(i==j){
        v[i].push_back(arr[i]);
     }
}

for(i=0;i<7;i++){
    for(j=0;j<v[i].size();j++){
        cout<<v[i][j]<<" ";
    }
    cout<<endl;
}


return 0;

int arr[]={1,10,5,12,17,18,19}; int t[]={1,0,0,0,0,0,0}; int i,j; vector<int>v[7]; v[0].push_back(1); for(i =1;i<7;i++){ for(j =0;j<i;j++){ if(arr[j]<arr[i]){ if(t[j]>=t[i]){ t[i]=t[j]+1; v[i].push_back(arr[j]); } } } if(i==j){ v[i].push_back(arr[i]); } } for(i=0;i<7;i++){ for(j=0;j<v[i].size();j++){ cout<<v[i][j]<<" "; } cout<<endl; } return 0;

这是c ++代码,时间复杂度是N ^ 2.我会想出更优雅(使用map with pair)解决方案而不是这个。那将是nlogn命令。我没有在这里编写代码,因为这将取决于数据密度。如果数据密集,那么我将编写该方法,否则它将始终正常工作。