首页 > 其他分享 >LIS-最长上升子序列

LIS-最长上升子序列

时间:2024-03-25 16:58:41浏览次数:9  
标签:int 元素 low 数组 LIS 序列 最长 dp

LIS(最长上升子序列)是一个经典的问题。

首先我们来介绍子序列的概念:

子序列指的是一个序列中,按照原顺序选出若干个不一定连续的元素所组成的序列。

LIS有两种算法模型:一种是复杂度为O(n^{^{2}})的dp模型,另外一种是复杂度为O(nlogn),利用二分实现的模型。

模型一:复杂度为O(n^{^{2}})的dp模型

我们首先定义状态:
我们定义dp[i]为以a[i]结尾的最长上升子序列长度。
设置 j为小于 i 的某一点,那么当 a[j] < a[i] 时,必然有,以 a[j]结尾的最长上升子序列,现在能以 a[i]结尾,并且长度+1
因为j < ia[j]< a[i],满足上升子序列的要求。
所以 dp[i]的一条转移路径为 dp[i]=dp[j]+1
但是  j是比i小的某一个值,所以转移到 dp[i]这一状态的值很多,我们要选择最优状态。所以 dp[i]的状态转移:
dp[i]=max(dp[j]+1,dp[i]);
那么当 a[j] > a[i]
此时肯定不满足上升子序列,所以 dp[i]dp[j]毫无关联。
由此我们可以写出 LIS 的算法:

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N=1e3+10;
int n;
ll a[N],dp[N];
int main()
{
  cin>>n;
  for(int i = 1;i <= n;i++) {
    cin >> a[i];
    dp[i]=1;
  }
  
  for(int i = 1;i <= n;i++)
  {
    for(int j = 1;j < i;j++)
      {
      if(a[i] > a[j]) dp[i]=max(dp[i],dp[j]+1);
      }
  }
  ll ans = 0;
  for(int i = 1; i <= n; i++){
    ans = max(ans,dp[i]);
  }  
  cout<<ans<<endl;
  return 0;
 }

模型二:复杂度为O(nlogn),利用二分实现的模型。

当数据量较大,使用常规的O(n^2)的LIS算法会超时
故采用二分+贪心的算法求解: 
维护一个low数组,low[i]表示长度为 i 的最长上升子序列的末尾元素
使用贪心思想来对low数组进行更新,核心思想是末尾元素越小,越容易凑出最长的子序列
遍历每一个元素,若当前元素比low[i]更大,则直接加入low数组的末尾 
若当前元素小于low[i],则从low数组中找到一个大于等于它的最小值将其替换
由于low数组是递增的,故使用二分算法进行搜索和替换
最终输出low数组的长度即为答案 。

注意此算法的缺陷:low数组只有长度是有意义的,其保存的元素是无意义的。

由此我们可以写出 LIS 的算法:

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const int N = 3e5 + 10;
ll a[N],low[N];

int main(){
  int n,length = 1;
  cin >> n;
  for(int i = 1; i <= n; i++){
    cin >> a[i];
  }
  low[1] = a[1];  //初始化,长度为1的子序列初始化为第一个元素 
  for(int i = 2; i <= n; i++){
    if(a[i] > low[length]){  //若当前元素大于low数组末尾元素,直接插入 
      low[++length] = a[i];  
    }else{   //若小于,则用low数组中刚好大于等于它的元素替换之 
      int index = lower_bound(low + 1, low + length + 1,a[i]) - low;  //获取插入位置下标 
      low[index] = a[i];  //替换 
    }
  }
  cout << length <<endl;  //输出low数组长度即为答案 
  return 0;
}

标签:int,元素,low,数组,LIS,序列,最长,dp
From: https://blog.csdn.net/m0_72972329/article/details/137017721

相关文章

  • Paper Digest|基于在线聚类的自监督自蒸馏序列推荐模型
    论文标题:LeaveNoOneBehind:OnlineSelf-SupervisedSelf-DistillationforSequentialRecommendation作者姓名:韦绍玮、吴郑伟、李欣、吴沁桐、张志强、周俊、顾立宏、顾进杰组织单位:蚂蚁集团录用会议:WWW2024ResearchTrack本文作者:韦绍玮|蚂蚁集团高级算法工......
  • P2642 双子序列最大和
    原题链接审题1.连续子序列:子序列必须连续2.最小长度为13.子序列之间至少隔一个数题解令\(presum[i]\)代表i及其之前的最大前缀和则第一步更新令\(presum[i]\)为必须包括i的最大前缀和,第二步更新令其为i及其之前的最大前缀和。sufsum同理最后枚举断点求和code#inclu......
  • Ajax 发送json格式数据以及发送文件(FormData)和自带的序列化组件: serializers
    前后端传输数据的编码格式(contentType)get请求数据就是直接放在url?后面的url?usernmae=junjie&password=123...可以向后端发送post请求的方式form请求ajax请求前后端传输数据的编码格式urlencodedformdatajson研究form表单:默认的数据编码格式是(urlencod......
  • 代码随想录算法训练营第五十七/天 | 516. 最长回文子序列,647. 回文子串
     动态规划最强总结篇!如今动态规划已经讲解了42道经典题目,共50篇文章,是时候做一篇总结了。关于动态规划,在专题第一篇关于动态规划,你该了解这些! (opensnewwindow)就说了动规五部曲,而且强调了五部对解动规题目至关重要!这是Carl做过一百多道动规题目总结出来的经验结晶啊......
  • Alist聚合网盘
    Alist是一款支持多种存储服务的文件列表程序,它允许用户将文件保存在本地存储、阿里云盘、OneDrive、GoogleDrive等多个平台上。对于需要将大文件分享且受限于免费云存储服务大小限制的用户来说,Alist提供了一个理想的解决方案,使其成为私人轻量级网盘分享应用的绝佳选择。生......
  • drf : 序列化类使用many参数的作用,源码解析
    序列化类使用many参数的作用views.pyfromrest_framework.viewsimportAPIViewfrom.serizlizerimportBookSerializersfromrest_framework.responseimportResponsefrom.modelsimportBooksclassBookView(APIView):defpost(self,request):print(r......
  • drf : 模型类序列化器 以及扩展用法。
    模型类序列化器:serializer的升级。注意,此时表模型自身的校验规则也将映射过来。只需要在serializers中写一个模型类序列化器即可。serializer.py#模型类序列化器#此序列化类和表模型有对应关系,映射classPublishModelSerializer(serializers.ModelSerializer):class......
  • drf : source,定制序列化字段以及反序列化新增。局部钩子(validate_字段名),全局钩子(va
    source,SerializerMethodField,局部钩子,全局钩子serialzer.py:source用处对应字段:起别名,用处2对应方法:在表模型中定义一个方法,source可以与其关联用处3对应方法:可以当做字段第三种方法的扩展用法:使用程度高。model.pyfromdjango.dbimportmodels#Createyourmo......
  • drf: 序列化和反序列化, Django Rest_Framework 介绍也安装及使用。
    序列化与返序列化序列化:将python中的数据类型转换成指定数据类型发送给别人返序列化:接收别人发送过来的数据,返序列化成我们所需要的格式。eg::前端js提供过来的json数据,对于python而言就是字符串,我们需要进行反序列化换成模型类对象,这样我们才能把数据保存到数据库中。DjangoR......
  • 代码随想录算法训练营Day54 ||leetCode 392.判断子序列 || 115.不同的子序列
    392.判断子序列 双指针遍历,比较简单易懂classSolution{public:boolisSubsequence(strings,stringt){inta=0,b=0;while(a<s.size()&&b<t.size()){if(s[a]==t[b]){a++;}......