最长递增序列LIS研究

来源:互联网 发布:域名在哪买都是一样的 编辑:程序博客网 时间:2024/06/09 18:58

   最长递增子序列(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[n],MaxV记录M[n]中的最小值),并对于数组中的每个元素考察其是哪个子序列的最大元素,二分更新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



0 0
原创粉丝点击