思路: 由于一般的动态规划时间复杂度是O(n^2)(哈哈哈哈 第一次用的就是这个!)用在这里由于n最大为50000 所以会超时 到这里我们可以用一个数组来动态维护这个最长上升的子序列,将你要输入的子序列一个一个按升序存入数组 如果发现当前要存入的数字x比数组最后一个还要大 那么直接存入数组,否则就将数组中按升序第一个大于x的数 用x替换掉(这里的替换我们可以用二分搜索来进行) 由于二分搜索的时间复杂度是log(n) 所以总的时间复杂度为O(n log(n) ); 下面举个例子
例如 -6 4 -2 10 5 ,我们假设用p数组来存储这个序列 那么 p[0] = -6; 我们发现4 比-6大我们就直接将之存入 则 p[1] = 4,现在到 -2 我们用将数组总第一个大于-2的数用-2替换掉 则 p[1] = -2 ,现在p[]= ( -6,-2 ); 之后再用同样的方法 最后的结果是p[] = ( -6 , -2 , 5 ), 这里可以得知 (-6,-2,10) 的长度与前面的答案一致 但是因为5比10 小 所以如果后面还有数可以继续拓展的话 很明显 5 之后可以存的更多的数( 好像有点啰嗦!还是直接上代码吧)
1 /* 2 //我们先来看一下第一次的超时代码 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 7 using namespace std; 8 typedef long long LL; 9 const LL maxn = 50005; 10 LL dp[maxn]; 11 LL m[maxn]; 12 LL n; 13 int main() 14 { 15 cin>>n; 16 for(int i=1;i<=n;i++) 17 { 18 cin>>m[i]; 19 dp[i] = 1; 20 } 21 for(int i=2;i<=n;i++) 22 for(int j=i;j>=1;j--) 23 if(m[i]>m[j]) 24 dp[i] = max(dp[i],dp[j]+1); 25 LL ans = 0; 26 for(int i=1;i<=n;i++) 27 ans = max(ans,dp[i]); 28 cout<<ans<<endl; 29 return 0; 30 } 31 32 */ 33 34 //优化后的代码 35 #include<iostream> 36 #include<algorithm> 37 #include<cstring> 38 39 using namespace std; 40 const int maxn = 50005; 41 int p[maxn],a[maxn]; 42 int n,len = 0; 43 int main() 44 { 45 cin>>n; 46 for(int i=0;i<n;i++) 47 cin>>a[i]; 48 p[0] = a[0]; 49 for(int i=1;i<n;i++) 50 { 51 if(a[i]>p[len])//当前数大于数组末尾的数 直接存入 52 p[++len] = a[i]; 53 else 54 { 55 int pos = upper_bound(p,p+len,a[i]) - p; 56 p[pos] = a[i];//将第一个大于当前数的目标用当前数替换掉 57 } 58 } 59 cout<<len + 1<<endl;//由于len是从0开始 所以答案要加一 60 return 0; 61 }