如何从给定的数组中打印最长的增加子序列(LIS)?

时间:2013-02-11 05:20:49

标签: c++ algorithm

我可以通过普通函数和递归函数打印LIS的长度。但我想在C ++中打印给定数组中的LIS子序列索引。

这是我找到LIS长度的函数:

int lis( int *arr, int n )
{
   int *lis, i, j, max = 0;
   lis = (int*) malloc ( sizeof( int ) * n );
   for ( i = 0; i < n; i++ )
      lis[i] = 1;
   for ( i = 1; i < n; i++ )
      for ( j = 0; j < i; j++ )
         if ( arr[i] > arr[j] && lis[i] < lis[j] + 1)
            lis[i] = lis[j] + 1;
   for ( i = 0; i < n; i++ )
      if ( max < lis[i] )
         max = lis[i];
   /* Free memory to avoid memory leak */
   free( lis );
   return max;
}

此处array[10]={7 6 2 3 4 1 8 5 9 10}

此处LIS Length=6

我想打印{2 3 4 6 8 9}

中的数字索引array[10](它不是它的arrray索引的序列,我想要打印的内容)

7 个答案:

答案 0 :(得分:5)

在为每个索引计算lis之后,取tmp值等于max,在lis数组上向后移动,每次找到等于max的元素时,将该索引添加到答案并减去tmp。因此,您将以相反的顺序获取索引数组。

示例代码:

int tmp = max;
std::vector<int> indexes;
for( i = n - 1; i >= 0; --i )
   if( lis[ i ] == tmp )
   {
      indexes.push_back( i );
      --tmp;
   }
std::reverse( indexes.begin(), indexes.end());

答案 1 :(得分:1)

要按顺序打印,您可以使用递归方法:调用:printLIS(lis,lis.length -1,arr,max)

public static void printLIS(int[] lis, int lisIndex, int[] arr, int max) {
    if(max == 0) {
        return;
    }
    if(lis[lisIndex] == max) {
        printLis(lis,lisIndex-1, arr, max-1);
        System.out.print(arr[lisIndex] + " ");
    } else {
        printLis(lis,lisIndex-1, arr, max);
    }

}

答案 2 :(得分:1)

void solution() {
  int n;
  cin >> n;
  vector<int> v(n);
  for (int &x : v) cin >> x;
  vector<int> dp(n, 1);
  int i = 0, j = 1;
  vector<int> par(n);
  for (int i = 0; i < n; i++) {
     par[i] = i;
  }
  for (int j = 1; j < n; j++) {
     for (int i = 0; i < j; i++) {
        if (v[j] > v[i] && dp[j] < dp[i] + 1) {
           dp[j] = dp[i] + 1;
           par[j] = i;
        }
     }
  }
  int mx = 1, idx = 0;
  for (int i = 0; i < n; i++) {
     if (dp[i] > mx) {
        mx = dp[i];
        idx = i;
     }
  }
  cout << mx << "\n";
  vector<int> seq;
  while (true) {
     seq.pb(v[idx]);
     if (par[idx] == idx) break;
     idx = par[idx];
  }
  reverse(seq.begin(), seq.end());
  for (int i = 0; i < mx; i++) {
     cout << seq[i] << " ";
  }
}

维护一个父级数组,然后从LIS逐个父级终止的索引向后退,直到到达parent [index] = index的索引。

答案 3 :(得分:0)

int lis( int *arr, int n )
{
   int *lis, i, j, max = 0, max_index = 0;
   int *print = (int*)malloc(sizeof(int)*n);
   lis = (int*) malloc ( sizeof( int ) * n );
   for ( i = 0; i < n; i++ ){
      lis[i] = 1;
        print[i] = -1
    }
   for ( i = 1; i < n; i++ )
      for ( j = 0; j < i; j++ )
         if ( arr[i] > arr[j] && lis[i] < lis[j] + 1){
            lis[i] = lis[j] + 1;
            print[i] = j;
        }
   for ( i = 0; i < n; i++ ){
      if ( max < lis[i] ){
         max = lis[i];
        max_index = i;
      }
    }
    while(max_index >=0){
        printf("%d ",lis[max_inc_index]);
        max_index = print[max_index];
    }
   /* Free memory to avoid memory leak */
   free( lis );

   return max;
}

使用另一个跟踪索引的数组,这些索引是最长子序列的一部分,然后遍历数组以打印所有相应的元素。

答案 4 :(得分:0)

可以声明动态数组,其长度等于递增序列的最大长度。阵列ANS将保持最长的增长序列。

int *ans=(int*)malloc(sizeof(int)*max);

临时变量用于保持数组中最大长度的索引。

    int index;
    int length; //used to fill array ANS in reverse order.
    for ( i = 0; i < n; i++ )
      {
          if ( max < lis[i] )
          {
              max = lis[i];
              index=i;
          }
      }
    length=max;
    ans[length-1]=arr[index];  //filling array from the last
                               //last element will be the greatest element
    length--;
    while(index>0)
    {
        for(i=index-1;i>=0;i--)
        {
            if(lis[i]+1==lis[index] && arr[i]<arr[index])
            {
                ans[length-1]=arr[i]; 
                index=i;
                length--;
                break;
            }
        }
    }
    for(i=0;i<max;i++)
    {
        printf("%d",ans[i]);
    }

这里的复杂度是O(n)而不是O(n2),即使它可能正在使用两个循环,因为我们在每次输入块时都将索引值更改为i。

答案 5 :(得分:0)

不是最好的方法,但是您可以尝试...

int lis(int ar[], int n) {

int max = INT_MIN;
int* lis = new int[n];
int* sub_arr = new int[n];

for (int i = 0; i < n; ++i)
    lis[i] = 1;

for (int i = 1; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
        if(ar[i] > ar[j] && lis[j] + 1 >= lis[i]) {
            lis[i] = lis[j] + 1;
            sub_arr[i] = j;
        }
    }
}

for (int i = 0; i < n; ++i) {
    if(max < lis[i])
        max = ar[i];
}

int k = 0;
stack <int> st;
for (int i = 0; i < n; ++i) {
    if(max == lis[i])
        k = i;
}

cout << "Longest Incresing Subsequence : ";

st.push(k);
while(k > 0) {
    st.push(sub_arr[k]);
    k = sub_arr[k];
}

while (!st.empty()) {
    cout << ar[st.top()] << ' ';
    st.pop();
}
cout << endl;

return max;
}

答案 6 :(得分:0)

如果有人对Java版本感兴趣。评论了解释。

rf_grid= {"n_estimators": np.arange(10,100,10),
  "max_depth": [None,3,5,10],
  "min_samples_split": np.arange(2,20,2),
  "min_samples_leaf" : np.arange(1,20,2),
  "max_features": [0.5,1,'sqrt','auto'],
  "max_samples" : [100]