Rosalind编程问题之计算集合中最长的递增元素子集。

Longest Increasing Subsequence

Problem:
A subsequence of a permutation is a collection of elements of the permutation in the order that they appear. For example, (5, 3, 4) is a subsequence of (5, 1, 3, 4, 2).

A subsequence is increasing if the elements of the subsequence increase, and decreasing if the elements decrease. For example, given the permutation (8, 2, 1, 6, 5, 7, 4, 3, 9), an increasing subsequence is (2, 6, 7, 9), and a decreasing subsequence is (8, 6, 5, 4, 3). You may verify that these two subsequences are as long as possible.

Given: A positive integer n≤10000 followed by a permutation π of length n.
Sample input

5
5 1 4 2 3

Return: A longest increasing subsequence of π, followed by a longest decreasing subsequence of π.
Sample output

1 2 3
5 4 2


题目给出了我们一个集合{5,1,4,2,3}。需要我们输出最长的递增子集和最长的递减子集。举个栗子,在该集合中{1,4}就是一个递增子集,在保留元素顺序的前提下,元素大小从左到右依次增大。但是该子集并不是最长递增子集,因为存在子集{1,2,3}有三个元素,而{1,4}仅有两个元素。因此子集{1,2,3}是集合{5,1,4,2,3}的最长递增子集。最长递减子集同理。

暴力穷举法

最简单的思路便是暴力穷举法。我们可以从集合中挨个遍历元素作为第一个元素,并暂时视其为最大值/最小值。如果后面的元素大于此,则将后者假定为最长递增/递减集合的元素纳入该集合,同时更新最大值/最小值。遍历结束后统计此时假定的最长递增集合元素数量。以此类推穷举所有递增集合后,我们只需要选取元素数最多的子集,则该子集为最长递增集合。

暴力穷举法要求的计算量庞大,运算时间长。以此题为例,将Rosalind给出的示例数据输入程序可以很快得到最终结果。但是Rosalind给出的实操数据可没有示例数据的数据量那么小。小编拿到的是一个8000多个数字组成的集合。应用此程序需要跑十多分钟,不可能在规定时间内(5min)提交答案,效率低下,因此需要后继算法提升。

小编推荐下面的动态规划法。


动态规划法

动态规划算法需要我们构建一个动态数组用以储存当递增到第i个元素时,组成递增集合所含有的最多元素个数。同时本题还需要建立一个动态集合,用以储存新增的递增/递减元素。当我们用指针i遍历数组permutation时,将指针i所指的元素与i以前的元素可以形成新的数组。如果新增的元素i的值大于i以前的元素j的值,则此时元素i可以与元素j继续构成递增数组/集合。

刚刚构建的动态集合用以储存新增的递增/递减元素,如果元素i的值大于i以前的元素j的值,那么元素i就可以加在元素j的动态集合中,从而形成元素i的动态集合。所形成的最大递增元素数List[i]可以由前i个比i小的List[j]推导,即List[i]=List[j].add[i]。下方示意图展示了动态数组的变化流程,思路上与动态集合的流程一致:


由于Java对于命令行的长度限制,读取输入数据时,我们采用IO流的方法,此方法在先前的博客中有所提及:Java读取空格分隔的数值并输出为数值类型的数组

实现代码如下:

public class Longest_Increasing_Subsequence动态规划 {public static void main(String[] args) {//1.读取数据并进行检查int[] permutationπ = BufferedReader("C:/Users/Administrator/Documents/Downloads/rosalind_lgis.txt");
//        System.out.println(Arrays.toString(permutationπ));//检查数据//2.最长递增序列longestIncrease(permutationπ);//3.最长递减序列longestDecrease(permutationπ);}public static void longestIncrease(int[] permutationπ){//2.建立动态规划数组int[] dp = new int[permutationπ.length];List<List<Integer>> increaseArray = new ArrayList<>();//建一个装集合的集合[学术程稻属]// 初始化increaseArray和dp数组List<Integer> start = new ArrayList<>();start.add(permutationπ[0]);increaseArray.add(start);dp[0] = 1;for (int i = 1; i < permutationπ.length; i++) {List<Integer> Tempincrease = new ArrayList<>();dp[i] = 1;for (int j = 0; j < i; j++) {//最长递增序列if (permutationπ[i] > permutationπ[j]) {dp[i] = Math.max(dp[j] + 1, dp[i]);if (Tempincrease.size()<increaseArray.get(j).size()){Tempincrease = increaseArray.get(j);}}}//!!!!构建临时集合以避免同名变量覆盖之前increaseArray集合中的数据List<Integer> Temp = new ArrayList<>();for (Integer ele : Tempincrease) {Temp.add(ele);}Temp.add(permutationπ[i]);increaseArray.add(Temp);
//            System.out.println(increaseArray);//检查数据}List<Integer> max = new ArrayList<>();for (List<Integer> ele : increaseArray) {if (max.size()<ele.size()){max = ele;}}for (Integer ele : max) {System.out.print(ele+" ");}System.out.println();}public static void longestDecrease(int[] permutationπ){//2.建立动态规划数组int[] dp = new int[permutationπ.length];List<List<Integer>> decreaseArray = new ArrayList<>();//建一个装集合的集合[学术程稻属]// 初始化increaseArray和dp数组List<Integer> start = new ArrayList<>();start.add(permutationπ[0]);decreaseArray.add(start);dp[0] = 1;for (int i = 1; i < permutationπ.length; i++) {List<Integer> Tempdecrease = new ArrayList<>();dp[i] = 1;for (int j = 0; j < i; j++) {//最长递减序列if (permutationπ[i] < permutationπ[j]) {dp[i] = Math.max(dp[j] + 1, dp[i]);if (Tempdecrease.size()<decreaseArray.get(j).size()){Tempdecrease = decreaseArray.get(j);}}}//构建临时集合以避免同名变量覆盖之前increaseArray集合中的数据List<Integer> Temp = new ArrayList<>();for (Integer ele : Tempdecrease) {Temp.add(ele);}Temp.add(permutationπ[i]);decreaseArray.add(Temp);}List<Integer> max = new ArrayList<>();for (List<Integer> ele : decreaseArray) {if (max.size()<ele.size()){max = ele;}}for (Integer ele : max) {System.out.print(ele+" ");}}//读取以空格分隔的数字,并保存到字符串数组中public static int[] BufferedReader(String path) {BufferedReader reader;String[] perm = new String[1];try {reader = new BufferedReader(new FileReader(path));String line = reader.readLine();String line2 = reader.readLine();perm = line2.split("\\s+");reader.close();} catch (IOException e) {e.printStackTrace();}int[] permutationπ = new int[perm.length];for (int i = 0; i < perm.length; i++) {int number = Integer.parseInt(perm[i]);permutationπ[i] = number;}return permutationπ;}
}

几乎在一瞬之间,答案就已经出现!!

改进的空间也是有的,例如本例中的dp数组。本文通过构建ArrayList increaseArray /decreaseArray 实现了动态储存,节省运算资源和储存空间。新建的dp数组用于保存最长递增序列的元素个数,能有助于输出最长递增集合个数,但在本题中对于输出最长递增集合元素没有帮助。故代码中可以省略,有兴趣的小伙伴可以自行尝试精简代码。

感谢大佬EmmettPeng对于动态规划的分析,思路讲解在这篇博客中写的十分详细:【Rosalind】Longest Increasing Subsequence - 动态规划算法(Dynamic Programming)初探.

Rosalind Java|Longest Increasing Subsequence动态规划算法相关推荐

  1. LeetCode Longest Increasing Subsequence(动态规划、二分法)

    问题:求数组的最长上升子序列问题 思路:第一种方法使用动态规划方法,用dp(i)来表示从0到i之间的最长上升子序列的长度.状态转移方程为dp(i)=max{dp(j)+1},其中0<=j< ...

  2. leetcode 300. Longest Increasing Subsequence | 300. 最长递增子序列(动态规划)

    题目 https://leetcode.com/problems/longest-increasing-subsequence/ 题解 难得有官方题解的一道题. 参考:https://leetcode ...

  3. leetcode(300)—— Longest Increasing Subsequence(最长递增子序列)

    参考 Python 解法: 动态规划 -- 最长递增子序列(LIS) 原题位置:Longest Increasing Subsequence | LeetCode OJ 题目的说明: 严格递增: 子序 ...

  4. Dynamic Programming之Longest Increasing Subsequence (LIS)问题

    Longest Increasing Subsequence(LIS)问题是一类常见的可使用Dynamic Programming解决的算法问题.这个问题是指在一个数字序列中,找到最大个数升序排列的子 ...

  5. 【暴力】LeetCode 300. Longest Increasing Subsequence

    LeetCode 300. Longest Increasing Subsequence Solution1:我的答案 暴力搜索,时间复杂度O(n2)O(n2)O(n^2) class Solutio ...

  6. HPU第三次积分赛-D:Longest Increasing Subsequence(DP)

    Longest Increasing Subsequence 描述 给出一组长度为n的序列,a1​,a2​,a3​,a4​...an​, 求出这个序列长度为k的严格递增子序列的个数 输入 第一行输入T ...

  7. [Swift]LeetCode673. 最长递增子序列的个数 | Number of Longest Increasing Subsequence

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  8. The Longest Increasing Subsequence (LIS)

    传送门 The task is to find the length of the longest subsequence in a given array of integers such that ...

  9. C++longest increasing subsequence 最长递增子序列的实现之二(附完整源码)

    C++longest increasing subsequence 最长递增子序列的实现 C++longest increasing subsequence 最长递增子序列的的实现完整源码(定义,实现 ...

最新文章

  1. linux默认shell类型转换,Linux中默认的shell如何切换为其他类型的shell
  2. Python使用sklearn构建广义线性模型:Tweedie回归(Tweedie regression)实战
  3. HashMap can be replaced with SparseArray--Android应用性能优化之使用SparseArray替代HashMap
  4. php如何设计一个日志类,一个简单php日志类
  5. 协同过滤算法_基于Mahout的协同过滤推荐算法
  6. 另一种思路比较2个日期是否相等的方式
  7. primefaces_Primefaces CommandLink
  8. 无线路由dns服务器地址,tplink无线路由器怎么设置DNS服务器地址
  9. Youtube视频推荐框架解读及若干算法细节
  10. 关于Handling Unit SAP包装
  11. 微信内置浏览器在ios10中不能播放视频问题(无解)
  12. 解决git push报错问题
  13. Unsupervised Domain Adaption of Object Detectors : A Survey
  14. Android Glide图片框架的使用
  15. 2099 找到和最大的长度为 K 的子序列
  16. 全路段感知、云控平台……京台高速到底有多智慧?
  17. linux绝育玩客云_绝育老母鸡(玩客云)PT下载补充。如何过新手考核
  18. 凸四边形上的双线性插值
  19. 两个整数相乘的java实现
  20. ❤️ 程序注释及格式化工具❤️

热门文章

  1. 32位64位Eclipse和jdk对应关系说明【初学者适用】
  2. β-环糊精衍生物接枝羟丙基壳聚糖水凝胶/羧基改性壳聚糖固载环糊精水凝胶微球的制备
  3. SequenceToSequence
  4. mv移动或重命名文件
  5. 虚拟机开机问题:开机时卡在启动窗口
  6. 使用微信公众号发送模板消息
  7. 微型计算机技术中 通过系统把CPU,【单选题】在微型计算机技术中,通过系统   把CPU、存储器、输入设备和输出设备连接起来,实现信息交换。...
  8. Mac 下 Docker搭建RAP2 记录
  9. 学习3D建模多久才能工作呢
  10. C++函数模板和模板函数、类模板和模板类