简体   繁体   English

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

[英]How to print Longest Increasing Subsequence(LIS) from a given array?

I can print the length of a LIS by a normal function and Recursive function.我可以通过普通函数和递归函数打印 LIS 的长度。 But I want to print that index of LIS subsequence in a given array in C++.但是我想在 C++ 中的给定数组中打印 LIS 子序列的索引。

Here is my function to find the length of 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;
}

here array[10]={7 6 2 3 4 1 8 5 9 10}这里array[10]={7 6 2 3 4 1 8 5 9 10}

here LIS Length=6这里LIS Length=6

I wanna print the index of numbers {2 3 4 6 8 9} ( its not the sequence its the arrray index , what i wanna print ) index of sequence in the array[10]我想打印数字的索引{2 3 4 6 8 9} (它不是序列,它是数组索引,我想打印) array[10]中序列的索引array[10]

After calculating lis for each index, take a tmp value equal to max, go backwards on lis array, and every time you find an element equal to max, add that index to the answer and decrement tmp.在为每个索引计算 lis 后,取一个等于 max 的 tmp 值,在 lis 数组上向后走,每次找到等于 max 的元素时,将该索引添加到答案中并减少 tmp。 Hereby you'll get the indexes array in reversed order.因此,您将以相反的顺序获得索引数组。

Example code:示例代码:

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());

To print in order you can use recursive approach: calling : printLIS(lis, lis.length -1, arr, max)要按顺序打印,您可以使用递归方法:调用: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);
    }

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

Maintain a parent array and go backwards from the index where the LIS ends parent by parent till you reach the index where parent[index] = index.维护一个父数组并从 LIS 以父结束父的索引向后,直到到达父 [index] = 索引的索引。

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

Use an additional array that keeps track of indices, that are part of the longest subsequence and then traverse the array to print all the corresponding elements.使用一个额外的数组来跟踪索引,索引是最长子序列的一部分,然后遍历数组以打印所有相应的元素。

A dynamic array can be declared with its length equal to maximum length of the increasing sequence.动态数组可以声明为长度等于递增序列的最大长度。 The array ANS will keep the longest increasing sequence.数组 ANS 将保持最长的递增序列。

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

A temporary variable is used to keep the index of the maximum length in the array.临时变量用于保留数组中最大长度的索引。

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

Here the complexity is O(n) and not O(n2) even though it may be using two loops as we are changing value of index to i whenever if block is entered.这里的复杂度是 O(n) 而不是 O(n2),即使它可能使用两个循环,因为每当进入 if 块时,我们都会将索引值更改为 i。

Not the best way but you can try it...不是最好的方法,但你可以试试...

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

If anyone interested in Java version.如果有人对Java版本感兴趣。 Commented for the explanation.评论了解释。

   public int lengthOfLIS(int[] nums) {
    if(nums.length == 0) return 0;
    // array to store sub-problem solution. L[i] stores the length
    // of the longest increasing sub-sequence ends with nums[i]
    int[] L = new int[nums.length];
    // used to print the actual LIS
    int[] P = new int[nums.length];

    // longest increasing sub-sequence having just one element has length 1
    Arrays.fill(L, 1);
    Arrays.fill(P, -1);

    // start from second element in the array
    for(int i=1; i<nums.length; i++) {

        // do for each element in sub-array nums[0..i-1]
        for(int j=0; j<i; j++) {
            // find longest increasing sub-sequence that ends with nums[j]
            // where nums[j] is less than the current element nums[i]
            // and it extends the original sub-sequence increasingly
            if(nums[j] < nums[i] && L[i] < L[j]+1) {
                L[i] = L[j] + 1;
                // store what index helped to extend L[i] 
                P[i] = j;
            }
        }
    }
     /* find the maximum LIS from L calculated also its index */
    int max=L[0], maxIndex=0;
    for(int i=1; i<nums.length; i++) {
        if(max<L[i]) {
            max=L[i];
            maxIndex=i;
        }
    }
    //starting from index of max-length LIS traverse back 
    //using P array populated earlier
    while (maxIndex >= 0) {
        System.out.print(nums[maxIndex]+", ");
        maxIndex = P[maxIndex];
    }
    return max;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM