最长不降子序列

原创 2015年07月07日 11:01:38

比如arr={1,5,8,2,3,4}的最长不降子序列是1,2,3,4

  • 动态规划的思路:用P[i]去记录以i结尾的最长的不降子序列的长度,比如arr中,P[0]=1;P[1]=2;P[2]=3;P[3]=2;P[4]=3;P[5]=4;

  • 那P是如何生成的:首先P数组初始化每个值都为1,因为每个数自身也算做长度为1的不降子序列;其次在算P[i+1]时要去找从0-i中哪些数比a[i+1]小,从这些元素的P中找到一个最大的P[j],则P[i+1]=P[j]+1就是当前以i+1结尾的最大的不降子序列长度了;最终在P中找到最大的值就是当前数组的最大的不降子序列的长度,同时可以输出这个子序列。

  • 代码如下:

int longest_increasing_sequence1(int a[], int n)
//最长不降子序列 O(N^2),能输出子序列的值
{
    int D[10] = { 1,1,1,1,1,1,1,1,1,1 };
    //记录到第i个数位置,最长子序列的长度
    for (int i = 1; i < n; i++)
    {
        for (int j = 0; j < i; j++)
        {
            if (a[j] <= a[i])//从头找比当前数小的数进行比较
            //<=考虑到了相同的数字也组成了不降序列
            {
                D[i] = ((D[j] + 1)>D[i]) ? (D[j] + 1) : D[i];
                //保证能得到当前最长的子序列
            }
        }
    }
    int max = 1;
    for (int i = 0; i < 10; i++)
        max = ((D[i]>max) ? D[i] : max);
    return max;
}
  • 另一种方法也是从网上得知的,比较巧妙,复杂度为O(nlogn),但是无法输出具体的子序列。思路如下:
    – 用数组D[size]去存长度为size的不降子序列,最后一位数最小的值是D[size];例如a[i]元素:

        if a[i]>=D[size]:size++;D[size]=a[i];
        else:find(D[j-1]<=a[i]<D[j]);D[j]=a[i];
    

    – 也就是说,如果要比较的数比当前最长不降子序列最后一位数的最小值要大,说明这个数可以被加入到这个子序列中去,那么直接将子序列的长度size+1且更新size+1时子序列最后一位的值;如果要比较的数小于子序列最后一位数的最小值,说明这个数只能去找较小的size的子序列,然后插入到这个较小的子序列中去,寻找较小的size=j的方法是二分查找的思想:从0-size中去二分,直到找到了这样一个j,使得D[j-1]<=a[i]< D[j],这样a[i]就可以放在D[j]上,更新D[j]=a[i],但此时size并不会更新;之所以等号放在D[j-1]这里是为了保证当a[i]与D[j-1]相等时,仍构成一个不降的序列。

  • 代码如下:

int b_search(int b[], int m, int k)//二分查找,找长度为m的b中,最小的大于l的数的坐标
//记住二分查找的两个写法:递归和非递归,递归情况形参有四个包括left和right指针,用if(l<=r)判断条件;非递归情况形参只有三个包括size即可,用while(l<=r)判断条件
{
    int l = 0;
    int r = m - 1;
    while (1 <= r)
    {
        int mid = (l + r) / 2;
        if ((b[mid - 1] <= k) && (b[mid] > k))
        //不能写成a<b<c的形式,这样即使出现了重复,也会将重复的数计入到总长度里
            return mid;
        else if (b[mid - 1]>k)
            r = mid - 1;
//即使l=b[mid],也可以让l=mid+1,因为最终还会比较l与l-1两者的范围
            l = mid + 1;
    }
    return 0;//如果比第一个数还要小,则返回-1
}

int longest_increasing_sequence2(int a[],int n)
//最长不降子序列O(nlogn) 无法输出子序列的值
{
    int D[10];
    D[0] = a[0];
    //D[[i]记录最长子序列的长度为i+1,且此序列最后一位最小的数为D[i]
    int size = 1;//记录最长子序列的长度为size=i+1
    for (int i = 1; i < n; i++)
    {
//如果比当前最大长度的最小值大,则长度加一
        {
            D[size] = a[i];
            size++;
        }
        if (a[i] < D[size - 1])
        //如果比当前最大长度的最小值小,去长度较小的里面找能否符合
        {
            int j = b_search(D, size, a[i]);
            D[j] = a[i];
        }
    }
    return size;
}

相关文章推荐

最长不降子序列问题

问题输入·设有由n个不相同的整数组成的数列,记为:a(1)、a(2)、……、a(n)且a(i)a(j) (ij)·若存在i1输出程序要求,当原数列给出之后,求出最长的不下降序列。例子数列3,18,7,...

最长不降子序列 LIS(Longest Increasing Subsequence) 动态规划与深度搜索

看清楚题意, 再做题。 我发现我总是给自己出题, 把题目的意思看成另一个, 哎, 结果又来一套说法. 这是我做poj 1836 Alignment, 繁衍出的. 注意:以下跟poj 1836题意不一...
  • fofu33
  • fofu33
  • 2013年04月05日 11:20
  • 738

最长不降子序列的NlogN的解法

这是一个很好的题目。题目的算法还是比较容易看出来的,就是求最长上升子序列的长度。不过这一题的数据规模最大可以达到40000,经典的O(n^2)的动态规划算法明显会超时。我们需要寻找更好的方法来解决是最...

最长不降奇偶交替子序列

动态规划强化的日子(1)最长不降奇偶交替子序列题目出处:BJFUOJ 1028 http://acm.bjfu.edu.cn/acmhome/problemdetail.do?&method=show...
  • Ivan_wb
  • Ivan_wb
  • 2015年10月22日 23:38
  • 255

HDU 5807(Revenge of LIS II)最长不降子序列

题目大意是找第二长不降子序列,如果两个序列数字一样但是数字在原序列下标不一样也算不同序列。 答案无非两种可能 1.等于最长序列长度  2.最长序列长度-1 情况分析: 1.第一次到达最长序列长度...

最长不降子序列---dp

问题描述:   给定一个字符串,求出其不降子序列的最大长度。 分析:   从后往前逆推: 06 对于n个数,我们可以分为n-1个阶段。 07...

[动态规划]最长不降子序列-NlogN算法

NlogN算法精髓在于设立数组

最长不降子序列

知行合一,自强不息   最长不降子序列     这题目是经典的DP题目,也可叫作LIS(Longest Increasing Subsequence)最长上升子序列或者 最长不下降子序列。很...

hdu 5324 Boring Class 2015多校联合训练赛3 分治,最长不降子序列,最小字典序

Boring Class Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot...

hdu4513 后缀数组求最长对称不降序列

后缀数组求最长回文的变体
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:最长不降子序列
举报原因:
原因补充:

(最多只允许输入30个字)