普通版本,简单易懂但是时间复杂度高, O ( n 2 ) O(n^2) O(n2),在第一次遍历的同时遍历之前的部分看新出现的元素能否加到之前出现的元素的序列之前。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],dp[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
dp[i]=1;//将以a[i]结尾的最长上升子序列的长度设为1
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
dp[i]=max(dp[i],dp[j]+1);//如果a[i]>a[j],说明a[j]可以加到以a[i]结尾的子序列后面
}
}
cout<<*max_element(dp+1,dp+1+n)<<endl;//取最大值
return 0;
}
用d数组记录长度为len的序列的最优结尾,每次出现一个新元素,就二分遍历该数组寻找新元素能够作为哪个长度的子序列的最优结尾,最后输出d数组大小即可。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e6+7;
const int inf=0x3f3f3f3f;
int a[N],d[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int len=1;d[1]=a[1];
for(int i=1;i<=n;i++)
{
if(a[i]>d[len])//如果a[i]大于目前最长上升子序列的最优结尾,那么长度加一,结尾替换
{
len++;
d[len]=a[i];//这里的d[N]数组记录的是长度为len的上升子序列的最优结尾
}
else//如果新出现的a[i]小于目前最长上升子序列的最优结尾
{
d[lower_bound(d+1,d+len+1,a[i])-d]=a[i];//二分查找将该结尾放到最优的位置,替换掉前面比他大的最优结尾,成为最优结尾
}
}
cout<<len<<endl;
}