您的位置:首页 > 其它

最长递增序列LIS研究

2015-05-11 16:36 218 查看
最长递增子序列(longest increase sequence LIS)是各种面试笔试中经常考的一种题目,相似题目也有最长递减子序列,最长递增后递减序列。本文将详细介绍几种方法,供大家参考,不足之处,敬请原谅。

最长递增子序列即求解一组数值中最长递增序列长度,如有这样一个数组:{1, 3,5,7, 2, 9},那么这个数组的最长递增子序列就是5,即1, 3, 5, 7,9。

方法一:DP(动态规划)

像LCS一样,从后向前分析,很容易想到,第i个元素之前的最长递增子序列的长度要么是1(单独成一个序列),要么就是第i-1个元素之前的最长递增子序列加1,可以有状态方程:

LIS[i] = max{1,LIS[k]+1},其中,对于任意的k<=i-1,arr[i] > arr[k],这样arr[i]才能在arr[k]的基础上构成一个新的递增子序列。

int dp[31]; /* dp[i]记录到[0,i]数组的LIS,本例中假设arr的长度为31 */
int lis;    /* LIS 长度 */ 
int LIS(int * arr, int size)
{
    for(int i = 0; i < size; ++i)
    {
        dp[i] = 1;
        for(int j = 0; j < i; ++j)
        {
            if(arr[i] > arr[j] && dp[i] < dp[j] + 1)
            {
                dp[i] = dp[j] + 1;
                if(dp[i] > lis)
                {
                    lis = dp[i];
                }
            }
        }
    }
    return lis;
}


方法二:排序+LCS(最长公共子序列:可参考:http://blog.csdn.net/v_JULY_v/article/details/6110269)

排序算法自己任意算法,LCS算法也是采用动态规划的思想去解决的。下面提供快速排序加LCS的代码:

void qsort(int * arr, int left, int right)
{
    if(left >= right)    return ;
    int index = left;
    for(int i = left+1; i <= right; ++i)
    {
        if(arr[i] < arr[left])
        {
            swap(arr,++index,i);
        }
    }
    swap(arr,index,left);
    qsort(arr,left,index-1);
    qsort(arr,index+1,right);
}
 
int dp[31][31];
 
int LCS(int * arr, int * arrcopy, int len)
{
    for(int i = 1; i <= len; ++i)
    {
        for(int j = 1; j <= len; ++j)
        {
            if(arr[i-1] == arrcopy[j-1])
            {
                dp[i][j] = dp[i-1][j-1] + 1;
            }else if(dp[i-1][j] > dp[i][j-1])
            {
                dp[i][j] = dp[i-1][j];
            }else
            {
                dp[i][j] = dp[i][j-1];
            }
        }
    }
    return dp[len][len];
}


方法三:DP+二分查找

维护一个数组MaxV[i],记录长度为i的递增子序列中最大元素的最小值(即可能存在n个长度为k的递增子序列,n个递增序列相应会有n个最大值M
,MaxV记录M
中的最小值),并对于数组中的每个元素考察其是哪个子序列的最大元素,二分更新MaxV数组,最终i的值便是最长递增子序列的长度。这个方法真是太巧妙了,妙不可言。

/* 返回MaxV[i]中刚刚大于x的那个元素的下标 */
int BinSearch(int * MaxV, int size, int x)
{
    int left = 0, right = size-1;
    while(left <= right)
    {
        int mid = (left + right) / 2;
        if(MaxV[mid] <= x)
        {
            left = mid + 1;
        }else
        {
            right = mid - 1;
        }
    }
    return left;
}
 
int LIS(int * arr, int size)
{
    MaxV[0] = arr[0]; /* 初始化 */
    len = 1;
    for(int i = 1; i < size; ++i) /* 寻找arr[i]属于哪个长度LIS的最大元素 */
    {
        if(arr[i] > MaxV[len-1]) /* 大于最大的自然无需查找,否则二分查其位置 */
        {
            MaxV[len++] = arr[i];
        }else
        {
            int pos = BinSearch(MaxV,len,arr[i]);
            MaxV[pos] = arr[i];
        }
    }
    return len;
}


参考:
http://blog.csdn.net/dlutbrucezhang/article/details/40143227 http://blog.csdn.net/v_JULY_v/article/details/6110269 http://www.ahathinking.com/archives/117.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: