最长递增子序列

问题描述:

    求数组中最长递增子序列

    例如:

        1,-1,2,-3,4,-5,6,-7

         最长递增子序列为:1,2,4,6

问题解决:

       对于这类最优化问题,可以考虑使用动态规划,需要查看问题是否满足动态规划的最优化原理和无后效性。显然最长递增子序列中的部分子序列也是最长递增子序列,满足最优化原理

无后效性,对于最长递增子序列中的元素,其前面的元素,不会影响到其后的元素,满足无后效性,因此可以使用动态规划。

方法一:

    将数组从小到大排序,设为arrayB,求解原数组arrayA的最长递增子序列的问题转换为求解arrayA与arrayB的最长公共子序列,复杂度O(nlogn+n^2)=O(n^2)

方法二:

    设数组array[]中前i个元素的最长递增子序列长度为LIS[i],那么

LIS[i+1]=max{1,LIS[k]+1},for any k<=i & array[i+1]>array[k]

方法三:

    方法二考察第i+1个元素时没有考虑前i个元素的分布,现在考虑前i个元素的分布。假设LIS[i]表示数组array[]中前i个元素最长递增子序列长度,MaxV[j],表示长度为j的所有递增子序列中最大值的最小值,那么:

    对前i个元素的任何一个递增子序列,如果这个子序列的最大元素比array[i+1]小,则将array[i+1]添加到该子序列中,构成一个新的递增子序列。

具体实现:

/**
*    求解数组的最长递增子序列
*    
*    问题满足动态规划的最优化原理和无后效性,可以使用动态规划来求解
*
*    假设在目标数组array[]的前i个元素中,最长递增子序列长度为LIS[i],那么:
*    LIS[i+1]=max{1,LIS[k]+1},array[i+1]>array[k],for any k<=i 也就是说,如果array[i+1]
*    大于array[k],那么第i+1个元素可以接在LIS[k]长的子序列后面构成一个更长的子序列。
*    array[i+1]本身至少可以构成一个长度为1的子序列。
*/

#include <iostream>
using namespace std;

int MaxLIS(int* array,int size)
{
    int max=array[0];
    for (int i=0;i<size;i++)
    {
        max=array[i]>max?array[i]:max;
    }
    return max;
}

/**
*    方法1:求解最长递增子序列的算法,复杂度O(N^2)
*    求解思路:
*        LIS[i+1]=max{1,LIS[k]+1},for any k<=i
*/
int LIS1(int array[],int size)
{
    int* LIS=new int[size];
    for (int i=0;i<size;i++)
    {
        LIS[i]=1;
        //执行:LIS[i+1]=max{1,LIS[k]+1},for any k<=i
        for (int j=0;j<i;j++)
        {
            if (array[i]>array[j]&&LIS[j]+1>LIS[i])
            {
                LIS[i]=LIS[j]+1;
            }
        }
    }

    return MaxLIS(LIS,size);
}


/**
*    方法2:求解最长递增子序列算法2,复杂度O(N^2)
*    求解思路:
*        方法1,考察第i+1个元素的时候,没有考虑前i个元素的分布情况。现在考察第i+1个元素
*        的时候考虑前面i个元素的情况,即对于前面i个元素的任何一个递增子序列,如果这个子序列的
*        最大的元素比array[i+1]小,则将array[i+1]添加到这个子序列的后面,构成一个新的递增子序列
*/
int LIS2(int* array,int size)
{
    int* maxV=new int[size+1];    //记录长度为k的子序列的最大元素为maxV[k]
    maxV[1]=array[0];
    maxV[0]=array[0]-1;    //简化数组

    int* LIS=new int[size];
    for (int i=0;i<size;i++)
    {
        LIS[i]=1;
    }

    int nmaxLIS=1;    //最长递增子序列长度
    for (int i=0;i<size;i++)
    {
        int j=nmaxLIS;
        //寻找array[i]需要添加的最长递增子序列
        for (;j>=0;j--)
        {
            if (array[i]>maxV[j])
            {
                LIS[i]=j+1;
                break;
            }
        }

        //array[i]添加到当前最长递增子序列
        if (LIS[i]>nmaxLIS)
        {
            nmaxLIS=LIS[i];
            maxV[nmaxLIS]=array[i];
        }
        else     //更新指定最长递增子序列长度,其中maxV[j]<array[i]<maxV[j+1]
        {
            maxV[j+1]=array[i];
        }
    }

    return nmaxLIS;
}

int main()
{
    int array[]={1,-1,2,-3,4,-5,6,-7};
    int size=sizeof(array)/sizeof(array[0]);

    cout<<"最长递增子序列长度Method1:"<<LIS1(array,size)<<endl;
    cout<<"最长递增子序列长度Method2:"<<LIS2(array,size)<<endl;
}
posted @ 2014-02-16 15:59  罗松超  阅读(1276)  评论(0编辑  收藏  举报