Longest Increasing Subsequence

来源:互联网 发布:maclc如何安装windows 编辑:程序博客网 时间:2024/04/25 16:26

  最长递增(递减)子序列问题,wangs说十分重要,在许多题目中,都会遇到此类问题的变形,我记得去年我在刷CF的时候,就遇到此类题目,当日还没学动态规划,尝试用贪心去解决,果断的超时。看了一份资料是关于动态规划的,第一个就讲的是最长子序列问题。查了一些资料,有了一些理解。

  在查资料之前,我推出的公式是:d[i]=d[j]+1,当j<i&&A[j]<A[i],其实思路是没错,但是应当考虑的是,在i之前的所有序列都应该遍历一遍,从而取最大值。

  所以正确的递推公式应该是:d[i]=max(d[j]+1), j<i&&j>0&&A[j]<A[i]; 因为在考虑到第i个时,如果第i个能够加入,那么我们就必须考虑到A[I]大于前面的子序列中的最大值,并且,我们得取前面的子序列长度的最大值,即转化到子问题前i-1项中小于等于A[I]的序列的最长序列。

  按照我的想法实现方法应该如下:

 

int LIS(){    int i,n,l;    for(i=0;i<5;i++)        d[i]=1;    for(i=0;i<5;i++)        for(int j=0;j<i;j++)        {            if(a[i]>=a[j])               d[i]=max(d[i],d[j]+1);                }                for(i=0;i<5;i++)                    if(l<d[i])                        l=d[i];                return l;}

  很明显该算法的复杂度是O(n^2);查了一些资料,还找到一个O(n^2)的递推公式,这个公式把我折磨惨了,花了一个晚上都没搞明白,最后还是学长一句话点醒我。

下面给大家介绍下我在另外一个博客看到的,虽然都是O(n^2)的算法,而且此算法将问题复杂化,但是我觉得把每一个正确的读懂,有利于思维吧!

 假设现在给定一个序列A,我们自己定义一个序列B,其中B是由A序列拷贝过来的,并且B序列经过排序得到是in order。

 现在我们假设S[i][j]表示在前i项中,且元素的最大值是B[j]的最长子序列的长度。

First : copy A to B;

        :make B in order ,

        :init S [1][j] ,j from 1 to n{ if(A[i]>B[j]) S[1][j]=0 else S[1][j]=1  }

Then  i -> 2 to n;

         j-> 1 to n;

         if(A[i]>b[j])  S[i][j]=s[i-1][j]   因为此时A[I]>B[j],而S[i][j]表示的是前i项中小于等于B[j]的最长子序列大小,固A[i]是不能加入

         else

         find the index k of A[i] in the B;

        S[i][j]=max(S[i-1][j],S[i-1][k]+1) 其实我纠结的地方是为什么这里是在K点,后来想明白,因为如果超过K点就可能导致A[I]小于B[j],而S[i][h](h>k)中的最大数就会大于A[i]。从而导致不能构成递增、这点坑了我好久。。。


        对于一般的数据,或许O(n^2)的算法能够算过,但是当数据范围增大时,就会导致时间超限,所以我们这里需要的是优化时间,

        二分法:

首先,我们需要明白一个道理,对于i项中,设最长的递增子序列的长度为s;

        设c数组中存的是长度有1-s的子序列的最大值。那么这个数组一定是递增的。

       设i-1项中,最长的递增子序列和为s;且最大的是c[s];

如果当前元素小于c[s],我们就在里面找一个比他第一小的,替换掉他。

这样的话就相当于压缩,减小规模,增加了后面的序列可增加性,

 但是当前元素大于的话,那么说明长度增加1,并且把当前的值赋值给c[s+1];

 int longest_increasing_sequence(int a[4000],int n){    int i,j,k,ans,m;       ans=0;    for(i=n;i>=1;i--)    {        j=1;        k=ans;        while(j<=k)        {            m=(j+k)/2;            if(b[m]>a[i])  j=m+1;            else    k=m-1;        }        if(j>ans)    ans+=1;        b[j]=a[i];    }       return ans;}

至于记录路径的神马的,明天再说吧!确实累了,今天一天就琢磨这一个题目。。。

人笨就是没办法啊!~~~

端午节到了!明天好好学一天算法,后天高数,外天大物,

Power Yes!KItty


 





0 0
原创粉丝点击