zoukankan      html  css  js  c++  java
  • 最长上升子序列(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)。
     

  • 相关阅读:
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    迷宫问题 POJ 3984
    UVA 820 Internet Bandwidth (因特网带宽)(最大流)
    UVA 1001 Say Cheese(奶酪里的老鼠)(flod)
    UVA 11105 Semiprime Hnumbers(H半素数)
    UVA 557 Burger(汉堡)(dp+概率)
  • 原文地址:https://www.cnblogs.com/DWVictor/p/10279676.html
Copyright © 2011-2022 走看看