動態規劃之最長上升子序列
阿新 • • 發佈:2018-12-24
問題描述
最長上升子序列(longest increasing subsequence),也可以叫最長非降序子序列,簡稱LIS,不是太難。即一個數的序列bi,當b1 < b2 < … < bS的時候,我們稱這個序列是上升的。對於給定的一個序列(a1, a2, …, aN),我們可以得到一些上升的子序列(ai1, ai2, …, aiK),這裡1 <= i1 < i2 < … < iK <= N,但必須按照一定。比如,對於序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。這些子序列中最長的長度是4,比如子序列(1, 3, 5, 8)。
解題思路與演算法思想
如果我們要用動態規劃解這道題的,首要要解決的問題有兩點
1.如果我們已知前這個序列的前k-1項組成的序列的全部資訊(也就是前k-1位每一位的最
長上升子序列),如何求第k項的最長上升子序列
2.如何設定一個邊界條件,使得這個向前遞迴的求法不至於無限迴圈
- 我們首先來解決第一個問題
第一個要考慮的 :就是將前k-1個元素組成的數集 個的最長上升子序列 進行判斷 判斷什麼呢?判斷第k個元素是否能夠一最後一項的身份成為新的最長子序列的一員 這樣就有涉及到一個問題: 我們需要一組二額外的整形去記錄前k-1個元素的最長上升子序列的最大元素是多少 如果>=第k個元素 那麼第k個元素無法加入 否則 可以加入
- 第二個問題也很好解決
顯然,如果進行到前1個元素的時候
- 這個元素的最長上升子序列毫無疑問的是1
程式模型的建立
通過遞迴的方式以此計算前x個的最長上升子序列並且一路爬升到n
資料結構的選用
- 陣列
程式設計流程
- 輸入資料
- 遞迴判斷
- 輸出結果
程式設計偽碼演算法
for(int i = 0 ;i<n ;i++) { if(a[i]<a[n]) { tem = we_find(i)+1 ; } else { swap(a[i],a[n]) ; tem = we_find(i) ; swap(a[i],a[n]) ; } if(tem>sum) { sum = tem ; } }
源程式編碼清單
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std ;
vector<int>a ;
vector<int>mark ;
int we_find(int n) ;
int main(void)
{
int n ;
scanf("%d",&n) ;
for(int i = 0 ;i<n ;i++)
{
mark.push_back(-1) ;
}
int tem ;
for(int i = 0 ; i<n ;i++)
{
scanf("%d",&tem) ;
a.push_back(tem) ;
}
for(int i = 0 ;i<n ;i++)
{
printf("%d\n",we_find(i)) ;
}
//printf("%d",we_find(a.size()-1)) ;
}
int we_find(int n)
{
int sum = 0 ;
int tem ;
if(n==0)
{
return 1 ;
}
//if(mark[n]!=-1)
//{
// return mark[n] ;
//}
else
{
for(int i = 0 ;i<n ;i++)
{
if(a[i]<a[n])
{
tem = we_find(i)+1 ;
}
else
{
swap(a[i],a[n]) ;
tem = we_find(i) ;
swap(a[i],a[n]) ;
}
if(tem>sum)
{
sum = tem ;
}
}
//mark[n] = sum ;
return sum ;
}
}
程式輸入、輸出
輸入:
7
1 7 3 5 9 4 8
輸出:
4
輸入輸出檔案,或程式執行結果截圖
時間與空間複雜度分析
時間複雜度:n^2
程式使用說明
總結與完善