lis 最长上升子序列

最长上升子序列式dp的一种可以说是最基本的题目

比如:给出一个数列a = {1,3,8,5,6,7,7,7,4,7,4,6,7,8}

显然他的子序列有n^2 个 其中最长的是4,6,7,8

我们给出n^2和nlogn两种做法

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int N = 10010;

int dp[N],a[N],n;

int main(){
 memset(dp,0,sizeof(dp));
 cin>>n;
 for(int i = 1;i <= n;i++){
  cin>>a[i];
 }
 dp[1] = 1;   //dp[i] 表示匹配第i的最长的上升子序列
 for(int i = 2;i <= n;i++){
  dp[i] = 1;    //显然对有每一位上升的序列至少为1
  for(int j = 1;j < i;j++){
   if(a[i] > a[j]){
    if(dp[i] < dp[j] + 1){
     dp[i] = dp[j] + 1;
    }
   }
  }
 } 
 int ans = 1;
 for(int i = 1;i <= n;i++){
  if(dp[i] > ans) ans = dp[i];
 }
 cout<<ans;
 return 0;
}

 下面是nlogn做法,构造一个辅助数组,随便nlogn做法·和dp没有什么关系

#include<iostream>
 #include<cstdio>
 #include<cstring>

using namespace std;

const int N = 10010;

int lis[N],ans,n,a[N];     //lis为辅助数组 记录长度为i的序列中最小的

void HalfDivide(int r,int l,int x);

int main(){
  memset(lis,0,sizeof(lis));
  cin>>n;
  for(int i = 1;i <= n;i++){
   cin>>a[i];
  }
  lis[1] = a[1];  
  ans = 1;
  for(int i = 2;i <= n;i++){
   if(lis[ans] < a[i]){
    ans++;
    lis[ans] = a[i];
   }
   else HalfDivide(1,ans,i);    //1 ans为左右边界,i为下标
  //利用二分优化复杂度
 }  
  cout<<ans;
  return 0;
 }

void HalfDivide(int r,int l,int x){  //如果lis比a[i] 小那么a[i]显然可以接在lis后
 int mid = (l + r) / 2;           //若不然,就找一个lis s.t. a[i]可以接在它的后面
 while(r < l){
  if(a[x] < lis[mid]){
   r = mid + 1;
  }
  else{
   l = mid;
  }
  mid = (l + r) >> 1;
 }
 }

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值