【问题标题】:How to print Longest Increasing Subsequence(LIS) from a given array?如何从给定数组打印最长递增子序列(LIS)?
【发布时间】:2013-02-11 05:20:48
【问题描述】:

我可以通过普通函数和递归函数打印 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] 中的序列索引

【问题讨论】:

  • 提示:lis[i] 在最长递增子序列中的最后一个条目的索引处达到最大值。

标签: c++ algorithm


【解决方案1】:

在为每个索引计算 lis 之后,取一个等于 max 的 tmp 值,在 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());

【讨论】:

    【解决方案2】:

    要按顺序打印,您可以使用递归方法:调用: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);
        }
    
    }
    

    【讨论】:

      【解决方案3】:
      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 的索引。

      【讨论】:

        【解决方案4】:
        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;
        }
        

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

        【讨论】:

        • 不! max_inc_index 未定义。
        【解决方案5】:

        可以声明一个动态数组,其长度等于递增序列的最大长度。数组 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),即使它可能使用两个循环,因为只要输入块,我们就会将 index 的值更改为 i。

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

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

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

            【讨论】:

              猜你喜欢
              • 2019-06-19
              • 2014-05-23
              • 1970-01-01
              • 2012-02-01
              • 1970-01-01
              • 2014-10-25
              • 2018-05-19
              • 1970-01-01
              • 2013-07-03
              相关资源
              最近更新 更多