問題描述
最長上升子序列(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
程序使用說明
總結與完善