首先引出一个例子

问题 :

  给你一个长度为 6 的数组 , 数组元素为 { 1 ,4,5,6,2,3,8 } , 则其最长单调递增子序列为 { 1 , 4 , 5 , 6 , 8 } , 并且长度为 5 。

分析 :

  题目所要找的递增子序列 , 想想有什么特点呢 ? 是不是会发现 所有的递增序列 ,前一个数一定小于后一个数 ,并且如果给所有从小到大的数标号 , 会得到一串递增的数 。

  既然是借助动态规划分析问题 , 那么当前的产生的结果 , 仅仅只与前一次状态有关 ,一直推的话 , 那么是不是就很自然地想到我最最简单的问题就是当数组中的元素只有一个的时候 , 并且我还要在开一个数组 , 记录所有元素的位置 。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std ; #define Min(a,b) a>b?b:a
#define Max(a,b) a>b?a:b int main ( ) {
int arr[7] = { 1 , 4 , 5 , 6 , 2 , 3 , 8 } ;
int pt[10] ; for ( int i = 0 ; i < 7 ; i++ )
pt[i] = 1 ;
for ( int i = 1 ; i < 7 ; i++ ) {
for ( int j = 0 ; j < i ; j++ ) {
if ( arr[i] > arr[j] && pt[j]+1 > pt[i] ) // 注意一定要是 pt[j]+1 > pt[i]
pt[i] = pt[j] + 1 ;
}
}
int maxn = 0 ;
for ( int i = 0 ; i < 7 ; i++ )
maxn = max ( maxn , pt[i] ) ; cout << maxn << endl ; return 0 ;
}

现在如果要输出这个递增的序列 , 要怎么做呢?

  

int maxn = 0 , t ;
for ( int i = 0 ; i < 7 ; i++ )
if ( maxn < dp[i] ) {
maxn = dp[i] ;
t = i ;
} for ( int i = 6 ; i >= 0 ; i-- ) {
if ( dp[i] == maxn ) {
cout << a[i] << '\t' ;
int f = a[i] , ff = dp[i] ;
for ( int j = i-1 ; j >= 0 ; j-- ) {
if ( f > a[j] && ff == dp[j]+1 ) {
cout << a[j] << '\t' ;
f = a[j] ;
ff = dp[j] ;
}
}
}
}

顺便给出 pt[ ] 数组中所存的数据

  

优化 :

  上述方法还是很好理解的 , 但是复杂度确实 n^2  , 现在有一种优化手段 , 可以将复杂度优化为 降为 n * log n ,这种方法的核心思想 ,  在二分下写 , 维护一个当前的最优的递增序列  , 找到恰好大于它的更新 。

举个小例子

  比如数组 a[ ] = { 1 , 3 , 2 , 4  } , 现将 a [ 1 ] 放入放入新数组 b [ ] 中 ,则 b[ 0 ] = 1 , 在 取出 a[ 1 ] = 3 , 将其放入 b 数组中 , 因为 3 恰好比 b[ 0 ] 大  , 所以 将 b[ 1 ] = 3  , 在拿出 a[ 2 ]  , 将 2 在数组 b 中二分 , 寻找位置 , 因为 2 恰好位于 1 和 3 之间 , 所以此时要用 2 去替换 3 的位置 ,即在 b 数组中得到一个新的有序的序列  , 但此序列并不是最长递增的子序列 ,它仅仅只是存储对应长度LIS 的最小末尾 。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std ; #define Min(a,b) a>b?b:a
#define Max(a,b) a>b?a:b int arr[7] = { 1 , 3 , 6 , 3 } ;
int dp[10] ; int fun ( int key , int l , int r ) {
int mid ;
if ( key >= dp[r] ) {
return r + 1 ;
}
while ( l <= r ) { // 二分查找,退出循环的前一次情况 , 一定是 l == r,如果 if 的判断里有等号 ,则 l 左移 ,否则 r 右移
mid = l + ( r - l ) / 2 ;
if ( dp[mid] <= key ) l = mid + 1 ;
else r = mid - 1 ;
} // printf ( "\n\n l = %d r = %d \n" , l , r ) ;
return l ;
} int main ( ) {
dp[0] = arr[0] ;
int len = 0 ;
for ( int i = 1 ; i < 4 ; i++ ) {
int f = fun ( arr[i] , 0 , len ) ;
dp[f] = arr[i] ;
if ( f > len ) len++ ;
} int cnt = 0 ;
for ( int i = 0 ; i < 4 ; i++ )
if ( dp[i] > 0 ) cnt++ ; cout << cnt << '\n' ;
return 0 ;
}

dp-最长递增子序列 (LIS)的更多相关文章

  1. 动态规划(DP),最长递增子序列(LIS)

    题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...

  2. 最长回文子序列LCS,最长递增子序列LIS及相互联系

    最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...

  3. 2.16 最长递增子序列 LIS

    [本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...

  4. 一个数组求其最长递增子序列(LIS)

    一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...

  5. 算法之动态规划(最长递增子序列——LIS)

    最长递增子序列是动态规划中最经典的问题之一,我们从讨论这个问题开始,循序渐进的了解动态规划的相关知识要点. 在一个已知的序列 {a1, a 2,...an}中,取出若干数组成新的序列{ai1, ai ...

  6. [DP]最长递增子序列

    #include <iostream> #include <limits.h> #include <vector> #include <algorithm&g ...

  7. 最长递增子序列LIS再谈

    DP模型: d(i) 以第 i 个元素结尾的最长递增子序列的长度. 那么就有 d(i) = max(d(j)) + 1;(j<i&&a[j]<a[i]),答案 max(d( ...

  8. 算法面试题 之 最长递增子序列 LIS

    找出最长递增序列 O(NlogN)(不一定连续!) 参考 http://www.felix021.com/blog/read.php?1587%E5%8F%AF%E6%98%AF%E8%BF%9E%E ...

  9. 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

    关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...

  10. HDU-1160-FatMouse's Speed(DP, 最长递增子序列)

    链接: https://vjudge.net/problem/HDU-1160 题意: FatMouse believes that the fatter a mouse is, the faster ...

随机推荐

  1. H3C 单路径网络中环路产生过程(1)

  2. http header详解,HTTP头、请求头、响应头、实体头

    Content-Language,Content-Length,Content-Type,Content-Encoding,mime分析 Accept 指定客户端能够接收的内容类型 Accept:te ...

  3. P1020 从大到小排序

    题目描述 给你n个整数,请你按照从大到小的顺序输出它们. 输入格式 输入的第一行包含一个整数 \(n(1 \le n \le 10^3)\) ,用于表示元素的个数. 输入的第二行包含 \(n\) 个整 ...

  4. Spring AOP 源码分析

    一.准备工作 在这里我先简单记录下如何实现一个aop:   AOP:[动态代理] 指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式: 1.导入aop模块:Spring AOP: ...

  5. H3C端口绑定技术简介

  6. Linux 内核端点

    USB 通讯的最基本形式是通过某些称为 端点 的. 一个 USB 端点只能在一个方向承载数 据, 或者从主机到设备(称为输出端点)或者从设备到主机(称为输入端点). 端点可看作一 个单向的管道. 一个 ...

  7. CF 453C. Little Pony and Summer Sun Celebration

    CF 453C. Little Pony and Summer Sun Celebration 构造题. 题目大意,给定一个无向图,每个点必须被指定的奇数或者偶数次,求一条满足条件的路径(长度不超\( ...

  8. vue-learning:14 - js - new Vue(options)中option

    new Vue(options)中option 2019-4-14 Vue的核心是数据驱动,在template中实现视图逻辑,在javascript中实现业务逻辑.要通过模板template将数据显示 ...

  9. JNDI数据源的使用

    有时候我们数据库的连接会使用jndi的方式 try { InitialContext ic = new InitialContext(); dataSource = (DataSource) ic.l ...

  10. iptables 基础

    SNAT 和 DNAT 是 iptables 中使用 NAT 规则相关的的两个重要概念.如上图所示,如果内网主机访问外网而经过路由时,源 IP 会发生改变,这种变更行为就是 SNAT:反之,当外网的数 ...