最长递增子序列
来源:互联网 发布:免费qq软件下载 编辑:程序博客网 时间:2024/05/22 05:06
最长递增子序列
题目描述
Redraiment是走梅花桩的高手。Redraiment总是起点不限,从前到后,往高的桩子走,但走的步数最多,不知道为什么?你能替Redraiment研究他最多走的步数吗?
样例输入
6
2 5 1 5 4 5
样例输出
3提示
从第1格开始走,最多为3步, 2 4 5
从第2格开始走,最多只有1步,5
从第3格开始走最多有3步,1 4 5
从第5格开始走最多有2步,4 5
所以这个结果是3。接口说明
方法原型:
int GetResult(int num, int[] pInput, List pResult);
输入参数:
int num:整数,表示数组元素的个数(保证有效)。
int[] pInput: 数组,存放输入的数字。
输出参数:
List pResult: 保证传入一个空的List,要求把结果放入第一个位置。
返回值:
正确返回1,错误返回0
思路1:
首先将【2、5、1、5、4、5】排序,得到【1,2,4,5,5,5】,然后求排序前后的最长公共子序列
【2、5、1、5、4、5】与【1,2,4,5,5,5】的最长公共子序列是【2,4,5】或【1,4,5】,刚好是最长递增子序列。
最长公共子序列的算法详见:http://blog.chinaunix.net/uid-26548237-id-3374211.html
1、序列str1和序列str2,长度分别为m和n
创建1个二维数组L[m.n],初始化L数组内容为0
m和n分别从0开始,m++,n++循环:
如果str1[m] == str2[n],则L[m,n] = L[m - 1, n -1] + 1;
如果str1[m] != str2[n],则L[m,n] = max{L[m,n - 1],L[m - 1, n]}
最后从L[m,n]中的数字一定是最大的,且这个数字就是最长公共子序列的长度2、从数组L中查找一个最长的公共子序列
i 和 j 分别从m,n开始,递减循环直到i = 0,j = 0。其中,m和n分别为两个串的长度。
如果str1[i] == str2[j],则将str[i]字符插入到子序列内,i–,j–;
如果str1[i] != str[j],则比较L[i,j-1]与L[i-1,j],L[i,j-1]大,则j–,否则i–;(如果相等,则任选一个)
不过,这种方法有一个问题,就是对于【1、1、1】这样的数组求解很麻烦。排序后仍为【1、1、1】,排序前后的最长公共子序列为【1、1、1】,但它的最长递增子序列为仅为【1】~
java 代码为:
// 对于【1、1、1】这样的数组求解有bugpublic static int GetResult_LCS(int num, int[] pInput, List pResult) { if(pInput == null || pInput.length != num) { return 0; } int[] temp = Arrays.copyOf(pInput, num); // 复制数组 Arrays.sort(pInput); // 排序 // LCS 最长公共子序列 int[][] arr = new int[num + 1][num + 1]; for(int i = 0; i < num + 1; i++) { arr[i][0] = 0; } for(int j = 0; j < num + 1; j++) { arr[0][j] = 0; } for(int i = 1; i < num + 1; i++) { for(int j = 1; j < num + 1; j++) { if(pInput[i-1] == temp[j-1]) { arr[i][j] = arr[i - 1][j - 1] + 1; }else { arr[i][j] = Math.max(arr[i][j-1], arr[i-1][j]); } } } pResult.add(arr[num][num]); return 1;}
思路2:
temp是一个数组,temp[i]表示以第 i 个元素为结尾的 最长递增子序列的长度。比如:
i = 0时,以2为结尾的最长递增子序列是:【2】,长度是1
i = 1时,以5为结尾的最长递增子序列是:【2、5】,长度是2
i = 2时,以1为结尾的最长递增子序列是:【1】,长度是1
i = 3时,以5为结尾的最长递增子序列是:【2、5】或【1、5】长度是2
i = 4时,以4为结尾的最长递增子序列是:【2、4】或【1、4】长度是2
i = 5时,以5为结尾的最长递增子序列是:【2、4、5】或【1、4、5】长度是3
综上,可以使用一个公式概括上述步骤:
扫描数组,对每一元素 i,
扫描它前面的所有元素 j,
如果 j < i 并且 temp[j] + 1 > temp[i],
那么 temp[i] =temp[j] + 1。
说明以 j 为结尾的最长递增子序列,在末尾加上i,就能构成一个更长的递增子序列。 比如:【2、4】加上【5】就能构成一个更长的子序列【2、4、5】
将上述思想转化为程序,Java代码如下:
import java.util.Scanner;import java.util.List;import java.util.LinkedList;public class Main { public static int GetResult(int num, int[] pInput, List pResult) { if(pInput == null || pInput.length != num) { return 0; } int[] temp = new int[num]; int max = 1; for(int i = 0; i < num; i++) { temp[i] = 1; for(int j = 0; j < i; j++) { if(pInput[j] < pInput[i] && temp[j] + 1 >= temp[i]) { temp[i] = temp[j] + 1; max = Math.max(max, temp[i]); } } } pResult.add(max); return 1; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()) { int n = sc.nextInt(); int[] array = new int[n]; for(int i = 0; i < n; i++) { array[i] = sc.nextInt(); } LinkedList<Integer> list = new LinkedList<>(); int result = GetResult(n, array, list); if(result == 1) { System.out.println(list.get(0)); }else { // TODO 错误处理 System.out.println(0); } } sc.close(); }}
显然,这个方法需要两层循环,时间复杂度是O(n^2)。我们还可以对其进行优化~
思路3:O(nlogn)
用一个数组h 保存“最小最长递增子序列”。原则:初始为第一个元素h=【2】,之后的每个元素,找到h中第一次比它大于等于的元素并替换它,如果没有则加在后面。
以【2,5,1,5,4,5】为例,
i = 0,h [0] = 【2】
i = 1,h [1] = 【2、5】
i = 2,h [2] = 【1、5】
i = 3,h [3] = 【1、5】
i = 4,h [4] = 【1、4】
i = 5,h [5] = 【1、4、5】
则最长递增子序列的长度为3
参考自 http://blog.csdn.net/qq_16949707/article/details/53045417
Java代码如下:
public static int GetResult_DPNLOGN(int num, int[] pInput, List pResult) { if(pInput == null || pInput.length != num) { return 0; } LinkedList<Integer> temp = new LinkedList<>(); temp.add(pInput[0]); for(int i = 1; i < num; i++) { boolean flag = true; for(int j = 0; j < temp.size(); j++) { if(pInput[i] <= temp.get(j)) { temp.set(j, pInput[i]); flag = false; break; } } if(flag) { temp.add(pInput[i]); } } pResult.add(temp.size()); return 1;}
牛客网里有一道题,就是有关最长递增子序列的,题中要求时间复杂度是O(nlogn)
https://www.nowcoder.com/practice/585d46a1447b4064b749f08c2ab9ce66?tpId=49&&tqId=29347&rp=2&ru=/activity/oj&qru=/ta/2016test/question-ranking
今天就到这里吧,拜拜~~
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 最长递增子序列
- 插入排序和插入排序的改进
- 割接
- laravel -- Eloquent 模型关联
- ListView中存在EditText,弹出键盘后焦点丢失问题。
- Centos7.3_64位安装Apache2.4_mysql5.7_php5.4(阿里云LAMP php环境搭建图文教程)
- 最长递增子序列
- 焦点图,轮播图效果
- 重构原则(一)
- 工程之间的跳转
- 数据结构实验之栈五:下一较大值(一)(二)
- Hibernate学习3 二级缓存和延迟加载
- Shell脚本语法篇
- 51 nod 区间交 (优先队列)
- 非对称加密