zl程序教程

您现在的位置是:首页 >  后端

当前栏目

最长上升子序列(LIS)

序列 最长 上升 LIS
2023-09-11 14:22:48 时间

点击打开链接

O(n^2)算法


dp[i] 以a[i]结尾的最长上升子序列

1·  只包含a[i] (1)

2·  在J<I 且 a[J]<a[I] dp[I]=dp[J]+1


状态转移方程

dp[I]=max (1, dp[J]+1|  J<I且 a[J]<a[J])



算法模板

//O(n^2)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 30010;
int dp[maxn], a[maxn];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;++i)  
            scanf("%d",&a[i]);  
        int ans=0;  
        for(int i=0;i<n;++i)  
        {  
            dp[i]=1;  
            for(int j=0;j<i;++j)  
            {  
                if(a[j]<a[i])  
                    dp[i] = max(dp[i], dp[j]+1);  //状态转化方程
            }   
            ans=max(dp[i],ans);  
        }  
        printf("%d\n",ans);  
}
return 0;




O(nlogn)算法


dp[i] i表示长度为i+1的末尾元素最小值

初始化 dp[i] = INF

a[j] i=0 ap[i-1]<a[j] dp[i]=min()


INF INF INF INF INF




//O(nlogn)
#include <cstdio>  
#include <algorithm>  
#define INF 0x3f3f3f  
using namespace std;  
int dp[30010],a[30010];  
int main()  
{  
    int n,i,j;  
    while(scanf("%d",&n)!=EOF)  
    {  
        for(i=0;i<n;++i)  
        {  
            scanf("%d",&a[i]);  
            dp[i]=INF;  
        }  
        for(i=0;i<n;++i)  
            *lower_bound(dp,dp+n,a[i])=a[i];  
        printf("%d\n",lower_bound(dp,dp+n,INF)-dp);   
    }  
    return 0;  

}