问题描述:
一个数的序列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:
时间复杂度O(n^2);
1 /* 2 dp[i]:以a[i]结尾的字符串长度; 3 有两种可能性; 4 1.只包含a【i】 5 2.附加到j<i&&a[j]<a[i],那么dp[i]=max(dp[j]+1,dp[i]) 6 */ 7 8 #include <iostream> 9 #include <cstdio> 10 #include <cstring> 11 using namespace std; 12 13 const int MAXN=100000; 14 const int INF=1<<30; 15 16 int a[MAXN]; 17 int dp[MAXN]; //代表以a【i】为结尾的序列的长度。 18 19 int main(){ 20 int n; //代表序列的个数 21 while(scanf("%d",&n)!=EOF){ 22 for(int i=0;i<n;i++) 23 scanf("%d",&a[i]); 24 25 memset(dp,0,sizeof(dp)); 26 27 int ans=-INF; 28 for(int i=0;i<n;i++){ 29 dp[i]=1; //这是只有a[i]; 30 for(int j=0;j<i;j++) 31 if(a[j]<=a[i]) 32 dp[i]=max(dp[j]+1,dp[i]); 33 ans=max(ans,dp[i]); 34 35 } 36 cout<<ans<<endl; 37 } 38 }
方法二:
时间复杂度:O(nlgn)
/* dp[i]:长度为i+1的上升子序列中末尾的最小值: 很明显长度i的子序列,其dp【i]越小,其在后面越占优势,而如何来更新dp【i】的值呢 上面一个算法,在查找的浪费了大量的时间, 这儿的dp数组的值明显是单调递增的。可以用二分搜索来查找,就可以把整个算法的时间复杂度,降低为O(nlgn); */ int bSearch(int num, int k) { int low=1, high=k; while(low<=high) { int mid=(low+high)/2; if(num>=dp[mid]) low=mid+1; else high=mid-1; } return low; } int LIS() { int low = 1, high = n; int k = 1; dp[1] = a[1]; for(int i=2; i<=n; ++i) { if(a[i]>dp[k]) dp[++k] = a[i]; else { int pos = bSearch(a[i], k); dp[pos] = a[i]; } } return k; } void solve(){ fill(dp,dp+n,INF); for(int i=0;i<n;i++) *lower_bound(dp,dp+n,a[i])=a[i]; //这是找到dp[i]>=a[i]的最小只真 printf("%d ",lower_bound(dp,dp+n,INF)-dp); }