數組中最長的升序子序列(動態規劃問題)

The longest Increasing Subsequence (LIS) 
給定一個序列,找到這個序列的一個最長的子序列,使得子序列的全部元素是升序的,且元素之間的相對位置不變(元素能夠在原數組中不相鄰,可是相對位置不變) 
好比, LIS for { 10, 22, 9, 33, 21, 50, 41, 60, 80 } 是 6,LIS 是 {10, 22, 33, 50, 60, 80}.ios

分析 
arr[0…n-1]是輸入,而後L(i)是到元素i爲止 LIS 的長度,也就是arr[i]做爲 LIS 的最後一個元素時 LIS 的長度,那麼用遞歸形式 L(i) 能夠寫做:數組

for(j<i)
    if(arr[j]<arr[i]) L(i) = {1+Max( L(j) )} 
if(j == 1) //遞歸的終止條件
    L(i) = 1

因此這個問題能夠將其分解爲 subproblems 用遞歸進行解決:spa

#include <iostream>
using namespace std;

int LIS(int *arr, int n, int *max_ref)
{
  if(n==1) return 1;
  int res, longest_here=1;

  for(int i = 1; i<n; ++i)
  {
    res = LIS(arr, i, max_ref);
    if(arr[i-1]<arr[n-1] && res+1>longest_here)
      longest_here = res+1;
  }

  if(*max_ref < longest_here)
    *max_ref = longest_here;

  return longest_here;
}

int main()
{
    int arr[] = { 10, 22, 9, 33, 21, 50, 41, 60 };
    int n = sizeof(arr)/sizeof(arr[0]);
    int max=1;
    LIS( arr, n, &max);
    cout<<max<<endl;
    return 0;
}

非遞歸方法,這個須要開闢額外的存儲空間。code

int LIS2(int *arr,int n)
{
  int *longest_here = new int[n]();
  longest_here[0] = 1;
  int max = 1;
  for(int i = 1; i<n; ++i)
  {
    for(int j = 0; j<i; ++j)
    {
      if(arr[j]<arr[i] && longest_here[j]+1>longest_here[i])
    longest_here[i] = longest_here[j]+1;

    }
    if(longest_here[i]>max)
      max = longest_here[i];
  }

  delete []longest_here;
  return max;

}

wiki上邊有時間複雜度爲O(nlog(n))的解法blog

相關文章
相關標籤/搜索