九度OJ 1533 最长上升子序列 (基于贪心和二分查找)

来源:互联网 发布:网络有利还是有害 编辑:程序博客网 时间:2024/06/05 05:44
题目描述:

给定一个整型数组, 求这个数组的最长严格递增子序列的长度。 譬如序列1 2 2 4 3 的最长严格递增子序列为1,2,4或1,2,3.他们的长度为3。

输入:

输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数n(1<=n<=100000):代表将要输入的序列长度
输入的第二行包括n个整数,代表这个数组中的数字。整数均在int范围内。

输出:

对于每个测试案例,输出其最长严格递增子序列长度。

样例输入:
44 2 1 351 1 1 1 1
样例输出:
21


【思路分析】

   求LIS的经典问题,用到的不是DP里面O(n*n)的方法,而是用了基于贪心、二分查找的O(nlogn)方法(为什么没有命名成XXX算法 = =)

   设a[n]为原序列,d[n]为长度为n的上升子序列的最后一个元素,当有多个长度为n的上升子序列时,取这些子序列中末尾最小的元素作为d[n]的值。为什么选最小的呢?因为最小的最有“潜力”(贪心)。举个例子,假设原序列为:2,1,8,3,7,5,6,对于d[3],长度为3的上升子序列有1,3,7和1,3,5两个,那么d[3]取值为5,即末尾最小的元素。因为在这个子序列后可能存在x满足 5 < x < 7(即x == 6),因此要是子序列确定为1,3,7的话,则显然不如1,3,5,6长。可见,d数组中的元素是单调递增的。

   有了上述的贪心策略,便可以进行下面的操作了。首先,令len = 1,d[1] = a[1],当a[i] > d[len]时,有d[++len] = a[i],即加入新的元素来扩充上升子序列;否则,从d[1]到d[len - 1]找到一个j,使得a[i]满足:  d[j - 1] < a[i] < d[j],这时有d[j] = a[i],即用a[i]来替换d[j](也就是a[i]比d[j]更有“潜力”)。又由于d数组是单调递增的,因此可以用二分查找O(logn)很快找到j的值。

   最后用a = {2,1,5,3,6,4,8,9}这个序列来过一遍上述的流程。首先,len = 1,d[1] = a[1] = 2。则a[i],len,d[len]的值的变化见下表:

  

代码如下:
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>using namespace std;const int maxn = 100005;int n;int a[maxn];int d[maxn];//记录长度为i的上升子序列最后一个元素的值int binSearch(int key,int left,int right){    while(left <= right)    {        int mid = (left + right) >> 1;        if(key > d[mid] && key <= d[mid + 1])//贪心策略        {            return mid;        }        else if(key > d[mid])        {            left = mid + 1;        }        else        {            right = mid - 1;        }    }    return 0;}int LIS(int n){    d[1] = a[1];    int len = 1;    int j = 0;    for(int i = 2;i <= n;i++)    {        if(d[len] < a[i])        {            j = ++len;//直接向后插入        }        else        {            j = binSearch(a[i],1,len) + 1;//找到替换位置        }        d[j] = a[i];    }    return len;}void init(){    for(int i = 1;i <= n;i++)    {        scanf("%d",&a[i]);    }}void solve(){    printf("%d\n",LIS(n));}int main(){    while(scanf("%d",&n) != EOF)    {        init();        solve();    }    return 0;}


  

  

0 0