zoukankan      html  css  js  c++  java
  • O(nlogn)LIS及LCS算法

         morestep学长出题,考验我们,第二题裸题但是数据范围令人无奈,考试失利之后,刻意去学习了下优化的算法

    一、O(nlogn)的LIS(最长上升子序列)

           设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A [t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A [t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有A [t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,更新D[k] = A[t]。

     不过这种方法要注意,D[]中并不是我们所求的最长上升子序列

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int search(int *a,int len,int n)
    {
    	int right=len,left=0,mid=(left+right)/2;
        while(left<=right)
         {
    			if (n>a[mid]) left=mid+1;
    		    else if (n<a[mid]) right=mid-1;
    		    else return mid;
    		    mid=(left+right)/2;
    	 }
    	return left;
    }//二分查找 
    
    int main()
    {
      int a[1000]={0},b[1000]={0};
      int n,i,j,mid,len;//len用来储存每次循环结束后已经求出值的元素的最大下标
       scanf("%d",&n);
       for (i=1; i<=n; i++)
       	scanf("%d",&a[i]);
       b[1]=a[1];
       b[0]=-1;
       len=1;//从第一位开始,目前只有第一位,所以len=1 
       for (i=1;i<=n;i++)
       	{
    		j=search(b,len,a[i]);
    		b[j]=a[i];
    		if (j>len) len=j;//更新len,由二分查找可知 ,len其实只须+1..... 
    	}
       printf("%d",len);
     return 0;
    }
    二、O(nlogn)的LCS


           其实就是把两个序列化成一个序列,然后做一遍上述O(nlogn)的LIS即可

    转换方法如下:

       有样例

          7 8

          1 7 5 4 8 3 9

          1 4 3 5 6 2 8 9

      数组a中 1  2  3  4  5  6  7

     分别对应1  7  5  4  8  3  9 不妨在数组b中的相同的数用在数组a中的 下标来表示(没有出现的用0)

    由上述描述则数组b原来为: 1  4  3  5  6  2  8  9

    可以表示为:                      1  4   6  3  0  0  5  7

    然后对处理后的数组进行一遍LIS,LIS中的len即为所求

    注意:这种O(nlogn)的LCS只适用于两两互不相同的两个序列之中,不然会退化(但可以维护二叉搜索树,然而我并不会/(ㄒoㄒ)/~~),但这种LIS是可重的

    下面是代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int a[100000]={0},c[100000]={0},d[100000]={0};
    
    int search(int *a,int len,int n)
    {
    	int right=len,left=0,mid=(left+right)/2;
        while(left<=right)
         {
    			if (n>a[mid]) left=mid+1;
    		    else if (n<a[mid]) right=mid-1;
    		    else return mid;
    		    mid=(left+right)/2;
    	 }
    	return left;
    }//二分查找 
    
    int main()
    {
      int n,m,i,j,mid,len;
       scanf("%d%d",&n,&m);
       for (i=1; i<=n; i++)
       {
    		scanf("%d",&a[i]);
    		c[a[i]]=i;
       }
       for (i=1; i<=m; i++)
       {
        	scanf("%d",&a[i]);
        	a[i]=c[a[i]];
       }
       d[1]=a[1];
       d[0]=-1;
       len=1;
       for (i=1;i<=m;i++)
       	{
    		j=search(d,len,a[i]);
    		d[j]=a[i];
    		if (j>len) len=j;
    	}
       printf("%d",len);
     return 0;
    }

    此处感谢morestep学长的倾情讲解



    ——It's a lonely path. Don't make it any lonelier than it has to be.
  • 相关阅读:
    node之body-parser的使用
    node解决跨域问题
    node之post提交上传
    HDU 6397(容斥原理)
    HDU 3374(最小最大表示法+KMP)
    HDU 6396(优先队列+思维)
    HDU 6395(矩阵快速幂)
    HDU 6370(并查集)
    HDU 6356(线段树)
    HDU 6354(计算几何)
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346284.html
Copyright © 2011-2022 走看看