一个人的角落,也许并没人会看到这里~~ 祝福你,工作顺心,学习快乐~

数据结构算法

动态规划-最长增长子序列

最长递增子序列(LIS)的问题是要找到一个给定序列的最长子序列的长度,使得子序列中的所有元素被排序的顺序增加。

例如,{2,1,0,5,4,8,9} LIS为{2,4,8,9},{2,4,8,9},{1,5,8,9}….最长长度为4。

这里存在一个局部前后无关性的规律:

设 arr[0..m..m+1] 其中arr[0..m] 的最长子序列是包含于arr[0..m+1]的,且长度包含

所以,求arr[0..m]的最长子序列,只需要找出{ arr[0..m-i],其中m=>i>=1}的LIS,

此时,设{ arr[0..m-i],其中m=>i>=1}的最长子序列:i = k;

如果arr[k] < arr[m]的话,则arr[m]的LIS长度为arr[0..k]的LIS长度+1;

LIS = LIS + arr[m];

int arr[10] = {2,1,0,5,4,8,9};
int n = sizeof(arr) / sizeof(arr[0]);

//返回包含第n个元素作为最后一个元素的子序列的最长长度,
//a用于记录最长长度,
int lis(int n, int &a)
{
    if(n == 1) return 1;
    int cmax = 0;
    for(int i = 1; i < n; i++)
    {
        //第n个元素有可能不是LIS的最后一个元素,所以这里的递归不能放进if里面。
        int r = lis(i,a);
        if(arr[i-1]<arr[n-1])
        {
            if(r > cmax) cmax = r;
        }
    }
    a = max(a,cmax+1);
    return cmax + 1;
}

可以看到,每次lis(n)的执行都会调用n-1次lis,时间复杂度为O(n^2), 下面进行优化: 方法与之前的背包问题和整分拆分问题非常相似。

int arr[10] = {2,1,0,5,4,8,9};
int nSize = sizeof(arr) / sizeof(arr[0]);
int lis2(int nSize)
{
    int *c;
    c = (int *) malloc(sizeof(int)*nSize);
    c[0] = 1;

    int gmax=0;
    for(int n = 1; n < nSize; n++ )
    {
        int cmax = 0;
        for ( int i = 0; i < n; i++ )
        {
            if ( arr[i]<arr[n] && c[i]>cmax ) 
                cmax = c[i];
        }
        c[n] = cmax + 1;

        if ( c[n] > gmax ) gmax = c[n];
    }

    free( c );
    return gmax;
}

01背包问题

恕在下愚钝,01背包问题学了两仨天才搞懂,其中也是断断续续了,

这个问题也是讲烂了的一个知识点,但是由于没有找到一个适合以自己的思维来理解的,所以现在总结一下

大家都说这是一个关于动态规划的问题,但在下才疏学浅,始终无法,理会这其中的关系,

唯一能联想到的就是高中的时候,学过的几何绘画动态规划了,特征是:给出限制条件,求最值。看来应该是这类题目了。

现在只考虑01背包的情况,至于动态规划的思想还要再接触几个相应的题目才能掌握。