序列的最长递增、递减序列

转自:


http://blog.csdn.net/tianshuai1111/article/details/7887810



一,题目

       求一个数组的最长递减子序列

               比如{94325432}的最长递减子序列为{95432}

      

       求一个数组的最长递增子序列

               比如{1,-1,2,-3,4,-5,6,-7}的最长递减子序列为{12436}

             


二,递增序列长度求解方法

       解法一:

                     时间复杂度为 o(n^2)

                     遍历数组序列,每遍历一个数组元素,则求序列到当前位置 最长的递增序列数,用temp[i]存储。

                     注意,当前的最长递增子序列受已经遍历的最长递增子序列影响,从序列头 再遍历到当前位置的前一个位置,挨个比较 a[j]与a[i](当前元素)大小,遇到小于a[i]且判断需要更新

temp[]数组。

     由于这里仅仅是求,最长递增序列的长度,所以仅仅用temp[]存储长度大小。

                                                                                                                                                                        源码:

 

[html]  view plain  copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. int LIS(int array[],int n)  
  5. {  
  6.     int temp[n];//存放当前遍历位置最长序列   
  7.     for(int i=0;i<n;++i)  
  8.     {  
  9.         temp[i]=1;   //初始化 默认长度   
  10.         for(int j=0;j<i;++j) //找出前面最长的序列   
  11.         {  
  12.             // 当前值 array[i] 跟已经遍历的值比较,  
  13.             //大于已经遍历的值且已知递增序列+1 大于当前值则 更新当前最长递增序列值   
  14.             if(array[i]>array[j]  && temp[j]+1 > temp[i] )  
  15.             {  
  16.                 temp[i] = temp[j] + 1;  
  17.             }  
  18.               
  19.         }  
  20.     }  
  21.       
  22.     int max=temp[0];  
  23.     for(int k=0;k<n;++k)//找出整个数组中最长的子序列   
  24.     {  
  25.         if(max<temp[k])  
  26.             max=temp[k];  
  27.     }  
  28.       
  29.     return max;  
  30.       
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     int arr[]={1,-1,2,-3,4,-5,6,-7};  
  36.     int result=LIS(arr,8);  
  37.     cout<<result<<endl;  
  38.       
  39. }  

       解法二:时间复杂度任然为 O(n^2)

      为了减少比较次数

      采用空间换时间的策略。新增一个数组MaxV[],max[i]表示所有长度为i的递增子序列中最大值之间的最小值

      nMaxlax记录当前最长子序列

      每次遍历一个元素时候,从最长子序列开始遍历,一直到1 比较当前元素值arr[i] 跟MaxV[j]的值,从而更新temp[]最长子序列和nMaxLax和MaxV[]的值

  源码:

[html]  view plain  copy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. int LIS(int array[],int n)  
  5. {  
  6.     int temp[n];//存放当前遍历位置最长序列   
  7.     int  MaxV[n]; //最长子序列中最大值之间的最小值  
  8.     MaxV[1]=array[0];//初始序列长度为1的子序列 中最大值的最小值  
  9.     MaxV[0]=-9999;//边界值  
  10.        
  11.      for(int i=0;i<n;++i)  
  12.     {  
  13.         temp[i]=1;   //初始化 默认长度   
  14.     }   
  15.      int  nMaxLis=1;  
  16.      int  j;   
  17.     for(int i=0;i<n;++i)  
  18.     {  
  19.         for(j=nMaxLis;j>=0;--j) //找出前面最长的序列   
  20.         {  
  21.             if(array[i]>MaxV[j])//当前值大于长度为j的子序列中最大值之间的最小值   
  22.             {  
  23.                 temp[i] = j + 1;  
  24.                 break;   
  25.             }  
  26.               
  27.         }  
  28.           
  29.         if(temp[i]>nMaxLis)//在最长子序列时停止 (这时只有一个最长的)   
  30.         {  
  31.             cout<<"nMaxLIs"<<nMaxLis<<endl;   
  32.               
  33.             nMaxLis=temp[i];  
  34.             MaxV[temp[i]]=array[i];   
  35.         }   
  36.         else if(MaxV[j] <array[i] && array[i]<MaxV[j+1])  
  37.         {  
  38.             MaxV[j+1]=array[i];   
  39.         }   
  40.     }  
  41.       
  42.       
  43.     return nMaxLis;  
  44.       
  45. }  
  46.   
  47. int main()  
  48. {  
  49.     int arr[]={1,-1,2,-3,4,-5,6,-7};  
  50.     int result=LIS(arr,8);  
  51.     cout<<result<<endl;  
  52.       
  53. }  

  解法三:

      将内循环查询部分换成二分搜索,则时间复杂度降低为 O(nlogN)


       解法四:

                     如5 1 6 8 2 4 5 10这一序列。

从第一个元素开始遍历,放到a数组中。即a[1]=5,接着遍历序列,第二个数是1 ,1<5 ,所以a[1]=1;

第三个数是6,6>1。所以a[2]=6。第四个数是8,8>1&&8>6,所以a[3]=8。第五个数是2 ,2>1&&2<6。所以a[2]=2......如此类推。最后a数组中存放的,就是最长的递增子序列。


                   例题:(https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1134)




基准时间限制:1 秒 空间限制:131072 KB 分值: 0  难度:基础题
 收藏
 关注
给出长度为N的数组,找出这个数组的最长递增子序列。(递增子序列是指,子序列的元素是递增的)
例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10。
Input
第1行:1个数N,N为序列的长度(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9)
Output
输出最长递增子序列的长度。
Input示例
8
5
1
6
8
2
4
5
10
Output示例
5

 

//AC
#include<iostream>
#include<cstring>
using namespace std;
int a[100000];
int b[100000];
int c[100000];
int main()
{
	int n,i,j;
	while(cin>>n)
	{
	    fill(b,b+n,1);
	    memset(c,0,sizeof(c));
		for(int i=0;i<n;i++)
		cin>>a[i];
		//int maxx=-1;
		c[0]=a[0];
		int l=0;
        for(int i=1;i<n;i++)
        {
            int z=0;
            for(int j=0;j<=l;j++)
            {
                if(a[i]<c[j])
                {
                    z=1;
                    c[j]=a[i];
                    break;
                } //cout<<c[j]<<" ";
            }
            if(!z)
            {
                l++;
                c[l]=a[i];
            }
            //cout<<endl;


        }
        /*for(int i=0;i<=l;i++)
            cout<<c[i]<<" ";
        cout<<endl;*/
        cout<<l+1<<endl;


		//cout<<maxx<<endl;

	}
	return 0;
}








三,递减序列 最长子序列求解方法

        用index数组,从大到小排序。然后依次遍历元素,查找元素在index数组中的位置pos ,根据位置来判断当前最长的子序列。

 

[html]  view plain  copy
  1. #include<iostream>  
  2. #include<cassert>  
  3. #include<stack>  
  4. using namespace std ;  
  5. int BiSearch(int *A,int nTarget,int nLen);  
  6.   
  7. void FindLongestSequence(int *A,int nLen)  
  8. {  
  9.     int *index=new int[nLen];//存放子序列   
  10.     int *LDS=new int[nLen];  
  11.       
  12.     index[0]=A[0];  
  13.     LDS[0]=1;  
  14.     int indexLen=1; //最长递增子序列 长度   
  15.       
  16.     for (int i=1;i<nLen;i++)  
  17.     {  
  18.         //这里是关键,在已经加入的 序列中查找当前序列的插入位置  
  19.            
  20.         int pos=BiSearch(index,A[i],indexLen);  
  21.           
  22.         index[pos]=A[i];  
  23.         LDS[i]=pos+1;//记录当前最长序列  
  24.            
  25.         if(pos>=indexLen)//插入的当前位置大于最长序列   
  26.             indexLen++;  
  27.     }  
  28.       
  29.     int ResultLen=indexLen;  
  30.     for (int i=nLen;i>=0;i--)//记录最长递减子序列   
  31.     {  
  32.         if(LDS[i]==ResultLen)  
  33.         {     
  34.             index[ResultLen-1]=A[i];  
  35.             ResultLen--;  
  36.         }         
  37.     }  
  38.   
  39.     for (int i=0;i<indexLen;i++)  
  40.     {  
  41.         cout<<index[i]<<" ";  
  42.     }  
  43.     delete []index;  
  44.   
  45. }  
  46. int BiSearch(int *A,int nTarget,int nLen)//二分搜索   
  47. {  
  48.     assert(A!=NULL&&nLen>0);  
  49.     int start=0;  
  50.     int end=nLen-1;  
  51.     while (start<=end)  
  52.     {  
  53.         int mid=(start+end)/2;  
  54.         if(nTarget>A[mid])  
  55.             end=mid-1;  
  56.         else if(nTarget<A[mid])  
  57.             start=mid+1;  
  58.         else  
  59.             return mid;  
  60.     }  
  61.     return start;  
  62. }  
  63. int main()  
  64. {  
  65.     int A[]={9,4,3,2,5,4,3,2,77,76};  
  66.     int nLen=sizeof(A)/sizeof(int);  
  67.     FindLongestSequence(A,nLen);  
  68.     return 1;  
  69. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值