LIS
题解:
最长不下降子序列,英文缩写为 LIS(Longest Increasing Subsequence)。其
定义是,设有由 n 个不相同的整数组成的数列,记为:
a(1)、a(2)、……、a(n)且 a(i)<>a(j) (i<>j)
例如 3,18,7,14,10,12,23,41,16,24。
若存在 i1<i2<i3< … < ie 且有 a(i1)<a(i2)< … <a(ie)则称为长度为 e 的不下
降序列。如上例中 3,18,23,24 就是一个长度为 4 的不下降序列,同时也有 3,7,10,
12,16,24 长度为 6 的不下降序列。程序要求,当原数列给出之后,求出最长的不下降序
列。
基本算法:
dp[i]表示以 a[i]结尾,能构成的最长不下降子序列长度。
初始: dp[i]=1;
转移: dp[i]=max(dp[j]+1) (1<=j<i);
因为 dp[i]表示以 a[i]为结尾,能构成的最长不下降子序列长度,所以求最终答案的
时候,还需要枚举 i,这样的做法时间复杂度是 O(n^2)。
优化算法:
例如数据为 4 7 3 5 8 2 6,我们可以定义另外一个辅助数组 h[i],表示当构造长
度为 i 上升序列时第 i 个数字最小值,这样,对刚才的数据,我们首先 h[1]=4,h[2]=7;
当扫描到 3 时,这个时候发现当构成一个长度的上升序列时,尾数越小越好,因为之后可
接数的可能性越大,因此 h[1]要更新为 3;当扫描到 5 时,同理,h[2]=5;扫描到 8 时,
h[3]=8;扫描到 2 时,h[1]=2;扫描到 6 时 h[3]=6,如下所示:
h[]={4, 7}
h[]={3, 7}
h[]={3, 5}
h[]={3, 5, 8}
h[]={2, 5, 8}
h[]={2, 5, 6}
这个辅助数组 h 最终长度即为最长上升序列的长度,并且我们发现辅助数组内的元素
时递增的,所以当我们要维护这个辅助数组时,有如下策略:
if(a[i]>h[len]) h[++len]=a[i]
else {
int p=search(1,len,a[i]);
//此处在 h 数组中二分搜索大于等于 a[i]的最小数值的下标
h[p]=a[i];
}
也就是说,维护 h 数组,我们只需要 logn 的时间复杂度,那么总的复杂度可以降低为
O(nlogn)。
代码1:
/*#include<bits/stdc++.h>
using namespace std;
int n,height[105],a_greater[105],a_less[105],res;
int find1(int l,int r,int x){
int ret=r;
while(l<=r){
int mid=(l+r)/2;
if(a_greater[mid]>=x){
ret=mid;
r=mid-1;
}
else l=mid+1;
}
return ret;
}
int find2(int l,int r,int x){
int ret=l;
while(l<=r){
int mid=(l+r)/2;
if(a_less[mid]<=x){
ret=mid;
l=mid+1;
}
else l=mid+1;
}
return ret;
}
void LIS_greater(){
for(int i=2;i<=n;i++){
for(int j=1;j<i;j++)
if(height[i]>height[j]) a_greater[i]=max(a_greater[i],a_greater[j]+1);
}
}
void LIS_less(){
for(int i=n-1;i>=1;i--){
for(int j=i+1;j<=n;j++)
if(height[i]>height[j]) a_less[i]=max(a_less[i],a_less[j]+1);
}
}
void optimized_LIS_greater_dichotomy(){
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&height[i]);
a_greater[105]=a_less[105]=1;
}
//合唱队形
LIS_greater();
LIS_less();
for(int i=1;i<=n;i++) res=max(res,a_greater[i]+a_less[i]-1);
printf("%d\n",n-res);
//严格递增序列
return 0;
}*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int up[105],down[105];
int n,a[105];
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]), up[i]=down[i]=1;
for(int i=2; i<=n; i++) {
for(int j=1; j<i; j++) {
if(a[i]>a[j])
up[i]=max(up[i], up[j]+1);
}
}
for(int i=n-1; i>=1; i--) {
for(int j=i+1; j<=n; j++) {
if(a[i]>a[j])
down[i]=max(down[i], down[j]+1);
}
}
int res=0;
for(int i=1; i<=n; i++) {
res=max(res,up[i]+down[i]-1);
}
printf("%d\n",n-res);
return 0;
}
代码2:
#include<bits/stdc++.h>
using namespace std;
int n,a[100005],h[100005],ht;
int find(int st,int ed,int v) {
int ret=ed;
while(st<=ed) {
int mid=(st+ed)/2;
if(h[mid]>=v) {
ret=mid;
ed=mid-1;
} else st=mid+1;
}
return ret;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
a[i]-=i;
}
h[ht=1]=a[1];
for(int i=2; i<=n; i++) {
if(a[i]>=h[ht]) h[++ht]=a[i];
else {
int p=find(1,ht,a[i]);
h[p]=a[i];
}
}
printf("%d\n",n-ht);
return 0;
}