最长上升/不下降子序列

最长上升/不下降子序列:(LIS)

有两种方法:

1.动态规划,O(n^2)

容易得出O(n^2)的DP递推公式:D[i]=max{D[j]}+1;(1<=j<i且E[j]<E[i])

D[i]为以元素i结尾的最长子序列个数。

这样经过两重循环一次遍历可以得到最长上升子序列。

代码:

View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnum=100;
 6 int a[maxnum],dp[maxnum];
 7 
 8 int main()
 9 {
10     int n,i,j;
11     scanf("%d",&n);
12     for(i=0;i<n;i++)
13     {
14         scanf("%d",&a[i]);
15         dp[i]=1;
16     }
17 
18     for(i=1;i<n;i++)
19         for(j=0;j<i;j++)
20             if(a[j]<=a[i])
21                 dp[i]=max(dp[i],dp[j]+1);
22 
23     int ans=dp[0];
24     cout<<dp[0]<<" ";
25     for(i=1;i<n;i++)
26     {
27         cout<<dp[i]<<" ";
28         if(ans<dp[i])
29             ans=dp[i];
30     }
31     cout<<endl;
32     printf("%d!!\n",ans);
33     return 0;
34 }
35 /*
36 7
37 3 2 5 4 4 6 7
38 */

2.二分查找法,CMI算法,O(nlogn)
操作:

开辟一个栈b,每次取栈顶元素s和读到的元素a做比较,如果a>s,则置为栈顶;如果a<s,则二分查找栈中的比a大的第1个数,并替换。最终栈的大小即为最长递增子序列为长度。

考察b栈内每个元素的含义,b[i] 表示所有长度为i的上升子序列中最后一个数最小的

举例:原序列为3,4,5,2,4,2

 栈为3,4,5,此时读到2,则用2替换3,得到栈中元素为2,4,5,再读4,用4替换5,得到2,4,4,再读2,得到最终栈为2,2,4,最终得到的解是:
 长度为1的上升子序列中最小的最后一个数是2 (2)
 长度为2的上升子序列中最小的最后一个数是2 (2,2)长度为3的上升子序列中最小的最后一个数是4 (3,4,4)
 可知没有长度为4的上升子序列,最长递增子序列长度为3. (3,4,4)
 
 CMI本质是LIS问题的另一种动态规划思路
 注意:CMI只能求LIS的长度和最后一个数,不能求LIS的序列!
代码:
View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnum=100;
 6 int a[maxnum];
 7 int stack[maxnum];
 8 int top=-1;
 9 
10 void function(int cur)
11 {
12     int l=0,r=top;
13     while(l<=r)
14     {
15         int m=(l+r)>>1;
16         if(stack[m]>=cur)  //递增,stack[m]>cur为非递减
17             r=m-1;
18         else
19             l=m+1;
20     }
21     if(l>top)
22         top=l;
23     stack[l]=cur;
24 }
25 
26 int main()
27 {
28     int n,i;
29     scanf("%d",&n);
30     for(i=0;i<n;i++)
31     {
32         scanf("%d",&a[i]);
33         function(a[i]);
34     }
35     printf("%d\n",top+1);
36     return 0;
37 }
38 
39 /*
40 6
41 3 4 5 2 4 2
42 */

 

转载于:https://www.cnblogs.com/pushing-my-way/archive/2012/08/27/2658174.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值