对于hdu 1950求LIS的问题,若使用常规的n^2算法会超时,所以需要用到LIS的nlogn算法求解。
一、
定义d[k]:长度为k的LIS的最小末尾元素,易知d中元素单调递增。
首先len=1,d[1]=a[1]。
对于a[i],若a[i]>d[len],则可将a[i]拼接在d[len]后成为更长的LIS,所以d[++len]=a[i];
否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],因为d是单调递增的,并且我们只需要替换d中某一个元素,显然此过程可以使用二分查找以降低时间复杂度为logn,则n个元素的复杂度为nlogn。
hdu1950:
#include<bits/stdc++.h>
#define MAXN 40005
using namespace std;
int d[MAXN],a[MAXN],len;
int binary_search(int i){
int left,right,mid;
left=0,right=len;
while(left<right){
mid = left+(right-left)/2;
if(d[mid]>=a[i]) right=mid;
else left=mid+1;
}
return left;
}
int main()
{
int T,n,i,j,k;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=1; i<=n; ++i) scanf("%d",&a[i]);
d[1]=a[1];
len=1;
for(i=2; i<=n; ++i){
if(a[i]>d[len]) d[++len]=a[i];
else{
int pos=binary_search(a[i]);
d[pos]=a[i];
}
}
printf("%d\n",len);
}
return 0;
}
二、
开一个数组,每次取数组末尾元素back和读到的元素temp做比较,如果temp>back则将back插入到数组末尾;
如果temp< back则二分查找数组中的比temp大的第1个数,并用temp替换它。这也是很好理解的,因为替换一个比temp大的数使得数组的''潜力''增大了——更容易找到更长的LIS。最长序列长度即为数组长度。
hdu1950:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,t,i;
int a[40005];
vector<int> v;
vector<int>::iterator it;
cin>>t;
while(t--){
cin>>n;
for(i=0;i<n;i++){
cin>>a[i];
}
v.push_back(a[0]);
for(i=1;i<n;i++){
if(a[i]>v.back()){
v.push_back(a[i]);
}
else{
it=lower_bound(v.begin(),v.end(),a[i]);
*it=a[i];
}
}
cout<<v.size()<<endl;
for(i=0;i<v.size();i++) cout<<v[i]<<' ';
v.clear();
}
return 0;
}