今天看了《挑战程序设计竞赛》的动态规划部分,感觉对以前一些知其然却不知其所以然的问题有了更好的理解,先整理一部分。

题意:

有一个长为n的数列a0,a1,a2,...,an 。请求出这个序列中最长的上升子序列的长度。上升子序列指的是对于任意的i<j都满足ai<aj的子序列。

分析:

设dp[i]为第i个下标之前的子串中最长上升子序列长度。得到递推关系式,时间复杂度O(n2)。

dp[i] = max(dp[i], dp[j] + 1) (a[i] > a[j])

代码:

#include<iostream>
using namespace std;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp, dp + n, 1);
for (int i = 0; i < n; i++){
for (int j = 0; j < i; j++){
if(a[i]>a[j])
dp[i] = max (dp[i], dp[j] + 1);
}
ans = max (dp[i], ans);
}
cout<<ans<<endl;
return 0;
}

分析:

还可以定义dp[i]为长度为i的上升子序列中末尾元素的最小值,对于长度相同的子序列,末尾元素越小,最终获得的上升子序列越可能长。从序列头开始对每个元素a[j]考虑上升子序列长度为0...i的情况,得到递推关系式,时间复杂度O(n2)。

 dp[i] = min(dp[i], a[j]) (a[j]>dp[i-1]||i==1)

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
dp[0] = a[0];
for(int j = 0; j < n; j++){
for(int i = 1; i <= n; i++){
if(i == 1||a[j] > dp[i-1])
dp[i] = min(dp[i], a[j]);
}
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}

分析:

上述方法中dp数组除INF外单调递增,所以对于每个元素,最多只更新一次dp数组, 而对于这次更新的位置,不必挨个遍历,可以直接二分查找下界,将复杂度降到O(logn)。

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int _binary_search(int l, int r, int num)
{
while(l < r){ //区间[l,r)
int mid = l + (r - l)/2;
if(dp[mid] >= num) r = mid;
else l = mid + 1;
}
return l;
}//获取下界
int main (void)
{
int n, ans = 0; cin>>n;
for (int i = 0; i < n; i++) cin>>a[i];
fill(dp + 1, dp + n + 1, INF);
for(int j= 1; j <= n; j++){
int pos = _binary_search(1, n+1, a[j]);
dp[pos] = a[j];
}
for(int i = n; i >= 1; i--){
if(dp[i] != INF){
cout<<i<<endl;
break;
}
}
return 0;
}

分析:

可以直接使用STL中的lower_bound获取下界。通过dp数组中INF的下界获取上升子序列长度。为方便表示可直接定义dp[i]为长度为i+1的上升子序列中末尾元素的最小值。有关 lower_bound 之前写过些简单介绍。

代码:

#include<iostream>
using namespace std;
const int INF=0x3fffffff;
int a[105], dp[105];
int main (void)
{
int n, ans = 0; cin>>n;
fill(dp, dp + n, INF);
for (int i = 0; i < n; i++){
cin>>a[i];
*lower_bound(dp, dp + n, a[i]) = a[i];
}
cout<<lower_bound(dp, dp +n, INF) - dp<<endl;
return 0;
}

【动态规划】最长上升子序列(LIS)的更多相关文章

  1. 动态规划——最长上升子序列LIS及模板

    LIS定义 一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1 ...

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

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

  3. 动态规划 - 最长递增子序列(LIS)

    最长递增子序列是动态规划中经典的问题,详细如下: 在一个已知的序列{a1,a2,...,an}中,取出若干数组组成新的序列{ai1,ai2,...,aim},其中下标i1,i2,...,im保持递增, ...

  4. 动态规划-最长上升子序列(LIS)

    时间复杂度为〇(nlogn)的算法,下面就来看看. 我们再举一个例子:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS长度. 我们定义一个B[i]来储存可能的排序序列,len为LIS长度. ...

  5. 动态规划--最长上升子序列(LIS)的长度

    l例如:对于[3,1,4,2,5],最长上升子序列的长度是3 arr = [3,1,4,5,9,2,6,5,0] def lis(arr): #dp[i]表示第i个位置的值为尾的数组的最长递增子序列的 ...

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

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

  7. nlog(n)解动态规划--最长上升子序列(Longest increasing subsequence)

    最长上升子序列LIS问题属于动态规划的初级问题,用纯动态规划的方法来求解的时间复杂度是O(n^2).但是如果加上二叉搜索的方法,那么时间复杂度可以降到nlog(n).  具体分析参考:http://b ...

  8. 2.16 最长递增子序列 LIS

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

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

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

  10. 最长上升子序列LIS(51nod1134)

    1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...

随机推荐

  1. 一个net程序猿必备工具

    自古以来,人类的进步都是依赖于工具的进步,从刀耕火种,到使用青铜器,再到现在的科技,每一次都使我们的工作效率提高了无数倍,所以一个好的工具能使我们提高无数倍的工作效率,下面,我就根据自己简单的总结一下 ...

  2. AJPFX关于代码块的总结

    代码块:        {                执行语句;        }(1) 当出现在局部位置时, 为局部代码块.        局部位置: 如语句块中, 函数中, 构造代码块中, 静 ...

  3. pandas 选择某几列

    转自:https://blog.csdn.net/aaa_aaa1sdf/article/details/77414387 col_n = ['名称','收盘价','日期'] a = pd.DataF ...

  4. 重构29-Remove Middle Man(去掉中间人)

    有时你的代码里可能会存在一些"Phantom"或"Ghost"类,Fowler称之为"中间人(Middle Man)".这些中间人类仅仅简单 ...

  5. OC中文件读取类(NSFileHandle)介绍和常用使用方法

    NSFileHandle 1.NSFileManager类主要对于文件的操作(删除,修改,移动,赋值等等) //判断是否有 tagetPath 文件路径,没有就创建 NSFileManager *fi ...

  6. HTML5——loading

    https://www.cnblogs.com/wangmeijian/p/4449150.html https://www.cnblogs.com/yunser/p/canvas-baidu-loa ...

  7. 泛型术语:占位类型placeholder

    Here’s a generic version of the same code: struct Stack<Element> { var items = [Element]() mut ...

  8. web pack 生成本地dist后 本地可以访问 路径由/ 改 ./

    config / index.js 里面将 / 改成 ./ 有两个 都改了 反正管用 然后npm run build 如果涉及到字体 css里面不会改 需要手工改成 ../../ 反正一般用到字体也不 ...

  9. 并发-5CAS与AQS

    juc: java.util.concurrent 锁: 悲观锁:写的比较多,对数据的增删改,读(查)少.Lock 乐观锁:反之,读多写少.版本 并发编程之 CAS 的原理 什么是CAS CAS (c ...

  10. 递归删除N天前的文件夹及子文件夹下的特定文件

    @echo offrem 设置被删除文件夹路径set SrcDir=D:\tmp\test\rem 设置文件保存天数set Days=2rem /p指定搜索文件的路径 /s 在子目录中搜索 /m 指定 ...