最长不降子序列

来源:互联网 发布:自学编程看什么书 编辑:程序博客网 时间:2024/04/30 22:41

比如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;}
0 0
原创粉丝点击