编程之美--数组中的最长递增子序列(LIS longest increasement sequence)
最早见到这道题目是在poj中,具体的题目忘记了,但是所要求的算法是一致的。
当时在学习LCS,因此想了一种和LCS比较相似的解法:
对原数组使用快速排序,然后使用LCS的思想求最大公共字串。 这种解法比较容易理解,但是所需要的空间为:O(2N) = O(N);时间为O(N^2+N*lgN) = O(N^2),显然这不是一种最优的解法。但是当时还真没有想到更好的解法……
最近看到编程之美上面的题目,然后豁然开朗。
书中提供了两个解法:
1. 根据无后效性的定义,可以使用DP来进行求解。根据递推公式:LIS[i+1] = max{LIS[i+1],LIS[k]+1} (当Data[i+1] > Data[k], 并且k∈[0,i]
在得出了上述的通项公式之后,可以简单的写代码求解了。但是这里需要注意的就是在for循环当中不停地更新当前的最大值,方便函数最后的结果返回。这个解法是传统的DP,因此时间复杂度为O(N^2),空间复杂度为O(N),但是在渐进意义上优于我的解法。
2. 当考虑前i个元素对i+1个元素的影响时,可以这样简答的理解:当子序列的最大元素比当前元素小时,就可以把当前元素添加到这个序列后面,构成一个新的LIS。
因此需要找到前i个元素的一个LIS,而且这个LIS的最大元素比Array[i+1]小,且长度尽可能的长。
为了加速算法的实现,构建一个长度为N的数组来维护长度为i的LIS的最大值。
因此该算法的时间复杂度是O(N^2),空间复杂度是O(2N) = O(N)。
上述算法的实现如下:
(二分查找的改进没有实现……)
//数组中最长递增子序列 #include <iostream> using namespace std; template<class T> inline T MaxInTwoElement(const T&a, const T &b) {return a>b?a:b; } int Slove1(const int *, int);//使用DP寻找,O(N^2), DP[i] = Max{DP[j]+1,DP[i]}(DP[i]>DP[j]) int Slove2(const int *, int);//使用另外的数组保存长度为n的LIS最大元素的最小值 int Slove3(const int *, int); int Dp[20]; void Initialize() {memset(Dp,0,sizeof(Dp));Dp[0] = 1; } int main() {int (*p[3])(const int*, int) = {&Slove1,&Slove2,&Slove3};int Data[] = {1,-1,2,-3,4,-5,6,-7};for (int i = 0;i<3;++i){cout<<p[i](Data,sizeof(Data)/sizeof(int))<<endl;}return 0; } int Slove1(const int *Data, int length) {Initialize();int Max = 1;for (int i = 1; i<length; ++i){for (int j = 0; j<i; ++j){if (Data[i] > Data[j]){Dp[i] = MaxInTwoElement(Dp[j] + 1,Dp[i]);}}Max = Max>Dp[i]?Max:Dp[i];}return Max; } int Slove2(const int *Data, int length) {int *MaxEle = new int[length +1];MaxEle[0] = -INT_MAX;MaxEle[1] = Data[0];//initializefor (int i =0; i<length; ++i)Dp[i] = 1;int maxLength = 1;for (int i=1; i<length; ++i)//traversing the array{int j;for (j=maxLength; j>-1; --j)//find the Max element int the LIS{if (Data[i] > MaxEle[j])//j is the length of sequence, too{//means it can be added to the sequenceDp[i] = j+1;break;}}//now j = 0 or the index which firstly satisfied Data[i] > MaxEle[j] if (Dp[i] > maxLength){//update the length and the element in MaxEle according to the lengthmaxLength = Dp[i];MaxEle[Dp[i]] = Data[i];}else if(Data[i] > MaxEle[j] && Data[i] < MaxEle[j+1]){//当前的值并不比最大长度大,则更新MaxEle[j+1] = Data[i];}}return maxLength; } int Slove3(const int *Data, int length) {int *MaxEle = new int[length +1];MaxEle[0] = -INT_MAX;MaxEle[1] = Data[0];//initializefor (int i =0; i<length; ++i)Dp[i] = 1;int maxLength = 1;for (int i=1; i<length; ++i)//traversing the array{int j; // int bg = 0; // int end = maxLength;//here, cuz the MaxEle is ordered( can be proved), //we can use binary search // while (true) // { // j = (bg +end)/2; // if (Data[i] > MaxEle[j]) // { // Dp[i] = j+1; // break; // } // else // { // end = j; // } // }for (j=maxLength; j>0; --j)//find the Max element int the LIS{if (Data[i] > MaxEle[j])//j is the length of sequence, too{//means it can be added to the sequenceDp[i] = j+1;break;}}//now j = 0 or the index which firstly satisfied Data[i] > MaxEle[j] if (Dp[i] > maxLength){//update the length and the element in MaxEle according to the lengthmaxLength = Dp[i];MaxEle[Dp[i]] = Data[i];}else if(Data[i] > MaxEle[j] && Data[i] < MaxEle[j+1]){//当前的值并不比最大长度大,则更新MaxEle[j+1] = Data[i];}}return maxLength; }
编程之美--数组中的最长递增子序列(LIS longest increasement sequence)相关推荐
- 编程之美 求数组中的最长递增子序列
如题,例如:存在数组 1,-1,2,-3,4,-5,6,-7 ,则最长的递增子序列是:1,2,4,6. 法一: 蛮力法 int Lis(int* arr,int n) {int iCount=0;// ...
- 求数组中的最长递增子序列
RT: 代码如下: 1 int lisq(int * a,int N) 2 { int e1=a[0],e2=a[0]; 3 int L1=1,L2=1; 4 int i; 5 6 for(i=1;i ...
- 耐心排序之最长递增子序列(LIS)
目录 一.问题引入 1.最长递增子序列(LIS) 2.问题分析 3.代码实现 4.问题思考 二.耐心排序 1.基本介绍 2.操作步骤 3.代码实现 三.俄罗斯套娃信封问题 1.题目描述 2.问题分析 ...
- vue3源码中的最长递增子序列
求解最长递增子序列是一道经典的算法题, 多数解法是使用动态规划的思想,算法的时间复杂度是O(); 而Vue.js内部使用的是维基百科提供的一套"贪心+二分查找"的算法; 贪心算法的 ...
- python最大连续递增子列_最长递增子序列(LIS)解法详述
求数组中最长递增子序列(Longest Increasing Subsequence, LIS) LIS问题是算法中的经典题目,传统的解法是使用动态规划,时间复杂度是O(n^2):改进的方法时间复杂度 ...
- 最长递增子序列LIS再谈
DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...
- 编程之美-求数组中最长递增子序列(LIS)方法整理
[试题描述] 方法一:时间复杂度O(n^2) 方法二:时间复杂度O(n^2) 方法三: 修改方法二中的穷举搜索部分为如下: 如果把上述查询部分利用二分搜索进行加速,可以得到时间复杂度为O(nlogn) ...
- 数组中的最长连续子序列
给定无序数组arr,返回其中最长的连续序列的长度(要求值连续,位置可以不连续,例如 3,4,5,6为连续的自然数) 示例1 输入 [100,4,200,1,3,2] 返回值 4 示例2 输入 [1,1 ...
- 动态规划 - 最长递增子序列LIS
问题:一个序列有N个数:A[1],A[2],-,A[N],求出最长非降子序列的长度 样例输入:3 1 2 6 5 4 思路: 首先把问题简单化.可以先求A[1],...A[i]的最长非降子序列,令dp ...
- 程序员面试100题之十二:求数组中最长递增子序列
写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长递增子序列为1,2,4,6. 分析与解法 根据题目要求, ...
最新文章
- C#调用COM组件遇到的问题及解决办法
- hardnet68尝试
- (一)Linux基本知识
- C++学习笔记7[指针]
- day4 Python的selenium库
- 解决vscode之前好好的能连接上linux服务器,后来报错,窗口出现故障
- 步步为营-75-Cookie简介
- VMware虚拟机CentOS7 - VMnet8网络配置及常见问题解决
- bzoj 1040: [ZJOI2008]骑士
- 复合索引失效的几种情况
- NetSuite 在中国 - 一个全程信息化管理平台
- 黑客攻防技术宝典:浏览器实战篇 -- 上篇(笔记)
- python 取整求余函数
- Android微信登录
- Python3---有关日期的处理---最近自然周最近自然月最近一周最近一月---dateutil模块
- AR体感大屏互动系统解决方案
- ISO/IEC 9126软件质量标准
- 手写一个迷你版的 Tomcat 喵
- 云服务器、VPS、虚拟主机三者之间的区别?
- JAVA综合性实验——猜姓氏游戏
热门文章
- 搜狗输入法双拼 linux,Ubuntu搜狗输入法设置双拼
- java图片黑白_java – 将图像转换为黑白图像
- 俄勒冈之旅_我在俄勒冈州SAO软件协会上通过A hrefhttpdbsaoorgcalendarofeventseventdescription进行介绍...
- python小组项目总结报告_项目总结报告多篇汇总
- 3Dmax2014安装问题
- 《Linux命令行与shell脚本编程大全(第3版)》读书笔记
- JavaScript(基础知识)
- shader编程-三维场景下SDF建模,对模型进行扭曲、弯曲、裁剪、掏空操作(WebGL-Shader开发基础12)
- 广东省高清卫星影像数据包下载
- R 单独窗口显示绘图(plots)