最长上升子序列(Longest increasing subsequence)


问题描述
        对于一串数A={a1a2a3…an},它的子序列为S={s1s2s3…sn},满足{s1<s2<s3<…<sm}。求A的最长子序列的长度。

动态规划法

算法描述:
        设数串的长度为n,L[i]为以第i个数为末尾的最长上升子序列的长度,a[i]为数串的第i个数。
        L[i]的计算方法为:从前i-1个数中找出满足a[j]<a[i](1<=j<i)条件的最大的L[j],L[i]等于L[j]+1。
动态规划表达式:


代码实现:

复制代码
int LIS(int a[], int n)
{
    int len[MAXSIZE];
    int i, j;
    int maxlen = 0;
    //计算以第i个数为结尾的最长上升子序列的长度
    for (i = 1; i <= n; i++)
    {
        len[i] = 0;
        //从前i-1个数中找出满足a[j]<a[i](1<=j<i)条件的最大的L[j]
        for (j = i-1; j >= 1; j--)
        {
            if (a[j] < a[i] && len[j] > len[i])
            {
                len[i] = len[j];
            }
        }
        len[i]++;
 
        if (len[i] > maxlen)
        {
            maxlen = len[i];
        }
    }
    return maxlen;
}
复制代码

 


上述算法的时间复杂度为O(n2)。

改进算法:
        在从前i-1个数中找出满足a[j]<a[i](1<=j<i)条件的最大的L[j]的时间复杂度为O(n),这里采用二分查找的方法对它进行优化,使其复杂度降为O(nlogn)。
        增设一个m[]数组,m[x]存放长度为x的最长上升子序列的最小末尾数。例:m[3] = 17表示长度为3的最长上升子序列的最小末尾数为17。
        由于子序列是上升的,所以m数组中的元素有一个性质,当x<y时,m[x]<m[y],利用这个性质来使用二分查找。
设m数组所存储的最长上升子序列的长度为k,当前计算的数为第i个
如果a[i]>m[k],则m[++k]=a[i];
否则在m[1~k]内二分查找小于(等于)a[i]的最大值的位置p,m[p]=a[i]。

代码实现:

复制代码
int BSearch(int a[], int n, int t)
{
    int low = 1;
    int high = n;
    
    while (low <= high)
    {
        int mid = (low + high) / 2;
        if (t == a[mid])
        {
            return mid;
        }
        else if (t > a[mid])
        {
            low = mid + 1;
        }
        else
        {
            high = mid - 1;
        }
    }
    return low;
}
 
int LIS_BSearch(int a[], int m[], int n)
{
    int maxlen = 1;        //最长上升子序列的长度
    m[maxlen] = a[1];
 
    int i;
    for (i = 2; i <= n; i++)
    {
        if (a[i] > m[maxlen])
        {
            m[++maxlen] = a[i];
        }
        else
        {
            //返回小于a[i]的最大值的位置p
            int p = BSearch(m, maxlen, a[i]);
            m[p] = a[i];
        }
    }
    return maxlen;
}
复制代码

 


改进后的算法时间复杂度为O(nlogn)。
 

posted @   DWVictor  阅读(705)  评论(0编辑  收藏  举报
编辑推荐:
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
阅读排行:
· 为DeepSeek添加本地知识库
· .NET程序员AI开发基座:Microsoft.Extensions.AI
· 精选4款基于.NET开源、功能强大的通讯调试工具
· 数据不出内网:基于Ollama+OneAPI构建企业专属DeepSeek智能中台
· 大模型工具KTransformer的安装
点击右上角即可分享
微信分享提示