当前位置:   article > 正文

lis 最长上升子序列

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;
 }
 }

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/1004954
推荐阅读
相关标签
  

闽ICP备14008679号