题目:

  输出最长递增子序列的长度,如输入 4 2 3 1 5 6,输出 4 (因为 2 3 5 6组成了最长递增子序列)。

  暴力破解法:这种方法很简单,两层for循环搞定,时间复杂度是O(N2)。

  动态规划:之前我们使用动态规划去解决一般是创建一维数组或者二维数组来构建出dp表,利用之前的历史上dp表中的值进行相关的处理求解出这个过程中的几个最大值,最小值,然后相加减来得出dp表的当前元素的值,所以我们会想,先创建一个一维数组,因为数组中选择的元素的范围在进行变化,所以dp表表示的值为截取到当前范围内最长的递增子序列是多少,但是在填表的过程中发现这种一般方法是不行的。但是这作为一道经典的题目,思路本身是很难的,有人想出来了它的dp解法,我们可以通过借鉴它的思路来帮助我们扩展理解dp算法。

  那么它的思路是:dp[i]表示的意思是必须包含以dp[i]结尾的最长递增子序列,那么它的值就是以dp[i]结尾的最长递增子序列长度。依次去扫描dp[i]这个字符之前的字符,假如发现当前字符大于之前的字符那么比较当前的最长子序列的长度与当前dp[i] + 1的值的大小来更新当前最长递增子序列的长度,当扫描完当前字符i之前的字符那么这个时候说明找到了以当前字符结尾的最长递增子序列的长度,把这个值赋值给dp[i]。

  需要注意的是最后还需要扫描一下dp数组,看一下哪一个dp[i]最大,因为我们不知道以哪个字符结尾的字符序列为最长的递增子序列,所以需要扫描一下,最后找到dp[i]的最大值返回,这是与之前的dp数组不同的一个点,以前是返回dp数组的最后一个元素就可以了,因为最后一个元素就是我们需要求解的最优解。这个解法时间复杂度也是O(N2)。
  那解法三的思路呢:dp[i]表示的是长度为i的最长递增子序列的末尾的那个数。先初始化dp[0]为数组中第一个元素的值,即dp[0]  =  4,定义一个指针p用来记录当前递增子序列的位置,从数组的第二个元素开始比较当前arr[i]与当前指针指向的dp数组的位置的值的大小,假如arr[i] > dp[p]那么说明当前的字符可以构成更长的递增子序列那么我们应该更新dp数组,指针往下移动,然后把当前的arr[i]的值赋值给dp[++p],假如arr[i] < dp[p]说明当前字符不能够构成更长的递增子序列,此时需要进行元素的替换,为什么进行替换呢?因为当前更小的元素更有利于最长递增子序列的贡献,所以扫描dp数组指向位置以及之前的位置假如arr[i] 大于dp[p]那么我们将其dp[p] 替换为arr[i]

  最后返回的是指针p指向的位置,注意返回最长递增子序列的长度是p指向的下标,这也是与之前动态规划的一般解法不同的点。更进一步的优化就是这种解法在扫描dp数组的过程中可以通过二分查找来降低时间复杂度,整体从O(N2)降低到O(NlgN)。
  代码:

package chapter_08_贪心策略与动态规划;

public class 最长递增子序列 {
static int[] arr = { 4, 2, 3, 1, 5, 6, 4, 8, 5, 9 }; public static void main(String[] args) {
System.out.println(f(arr)); // 输出 6
System.out.println(dp(arr)); // 输出 6
System.out.println(dp1(arr)); // 输出 6
} // 暴力破解法
private static int f(int[] arr) {
int maxCnt = 0;
for (int i = 0; i < arr.length; i++) {
int p = i;
int cnt = 1;
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] > arr[p]) {
cnt++;
p = j;
}
}
// if (cnt>maxCnt){
// maxCnt=cnt;
// }
maxCnt = Math.max(maxCnt, cnt);
}
return maxCnt; } static int[] dp = new int[arr.length]; // 解法二
private static int dp(int[] arr) {
dp[0] = 1; for (int i = 1; i < arr.length; i++) {
int cnt = 1;
for (int j = i - 1; j >= 0; j--) {
if (arr[i] > arr[j]) {
cnt = Math.max(cnt, dp[j] + 1);
}
}
dp[i] = cnt; }
int ans = -1;
for (int i = 0; i < dp.length; i++) {
ans = Math.max(ans, dp[i]);
}
return ans;
} // 解法三
/* 在优化之后,可以达到O(NlgN) */
private static int dp1(int[] arr) {
dp = new int[arr.length + 1];
dp[1] = arr[0];// 长度为1的最长递增子序列,初始化为第一个元素
int p = 1;// 记录dp更新的最后位置
for (int i = 1; i < arr.length; i++) {
if (arr[i] > dp[p]) {
dp[p + 1] = arr[i];
p++;
} else {
//扫描dp数组,替换第一个比arr[i]大的dp
//for (int j = 0; j <= p; j++) {
// if (dp[j] > arr[i]) {
// dp[j] = arr[i];
// }
//}
// 二分查找,比上面扫描dp数组耗时少
int indexOfFirstBigger = indexOfFirstBigger(dp, arr[i], 0, p);
if (indexOfFirstBigger != -1)
dp[indexOfFirstBigger] = arr[i];
}
} return p;
} /**
* 在递增数组中,从左查找第一个比v大的元素的下标
*/
public static int indexOfFirstBigger(int[] dp, int v, int l, int r) {
while (l <= r) {
int mid = (l + r) >> 1;
if (dp[mid] > v) {
r = mid; // 保留大于v的下标以防这是第一个
} else {
l = mid + 1;
}
if (l == r && dp[l] > v)
return l;
}
return -1;
}
}

  

  

动态规划----最长递增子序列问题(LIS)的更多相关文章

  1. 最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

    最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字 ...

  2. 最长递增子序列(LIS)(转)

    最长递增子序列(LIS)   本博文转自作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   --- 最长递增子序列又叫做最长上升子序列 ...

  3. [51Nod 1218] 最长递增子序列 V2 (LIS)

    传送门 Description 数组A包含N个整数.设S为A的子序列且S中的元素是递增的,则S为A的递增子序列.如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS).A的LIS可 ...

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

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

  5. 求解最长递增子序列(LIS) | 动态规划(DP)+ 二分法

    1.题目描述     给定数组arr,返回arr的最长递增子序列. 2.举例     arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,8,9}. 3.解答      ...

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

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

  7. Python动态规划求解最长递增子序列(LIS)

    原始代码错误,移步博客查看O(N^2)及优化的O(N*logN)的实现:每天一道编程题--最长递增子序列

  8. 动态规划之最长递增子序列(LIS)

           在一个已知的序列{ a1,a2,……am}中,取出若干数组成新的序列{ ai1, ai2,…… aim},其中下标 i1,i2, ……im保持递增,即新数列中的各个数之间依旧保持原数列中 ...

  9. hdu1257最少拦截系统 动态规划(最长递增子序列(LIS))

    Problem Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高 ...

随机推荐

  1. No grammar constraints (DTD or XML Schema) referenced in the document.

    问题描述 web.xml 使用 Servlet4.0 版本,No grammar constraints (DTD or XML Schema) referenced in the document. ...

  2. 防XSS攻击解决方法

    1.web.xml文件中新增filter配置 <!-- URL请求参数字符过滤或合法性校验 --> <filter> <filter-name>XssFilter& ...

  3. PADS Layout VX.2.3 制作PCB封装(Decal)时,导入DXF文件

    操作系统:Windows 10 x64 工具1:PADS Layout VX.2.3 进入PCB封装编辑器(Decal Editor),点击Drafting Toolbar > Import D ...

  4. 方法总结:如何实现html页面自动刷新

    使用场景: 1. 页面需要定时刷新,实时加载数据,需要实时查看监控数据(H5中的WebSocket和SSE可以实现局部刷新) 2. 一定时间之后跳转到指定页面(登录注册之类) 3. 前端开发使用伪数据 ...

  5. jsonp实现跨域资源共享原理

  6. STL 贺习笔记

    贺文链接www.cnblogs.com/zhouzhendong/p/STL.html C++ STL 的一些基础用法 前言 ​ 创建一个空的 vector ,我一直是这样写的: vector < ...

  7. UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...

  8. Django“少折腾”

    1.Django中文语言.时区 修改项目setting文件 LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai'

  9. Sightseeing trip POJ - 1734 -Floyd 最小环

    POJ - 1734 思路 : Floyd 实质 dp ,优化掉了第三维. dp [ i ] [ j ] [ k ] 指的是前k个点优化后    i  ->  j   的最短路. 所以我们就可以 ...

  10. hashMap 方法详解

    http://www.iteye.com/topic/754887 /** * 扩展散列表的容量 * @param newCapacity */ void resize(int newCapacity ...