Rosalind习题:Longest Increasing Subsequence(题目ID:LGIS)
今天突然发现自己的Rosalind的生物信息学的习题已经做到一个瓶颈了,感觉从今天的这道题开始难度开始大了,这种难度不是体现在需要多么高的代码水平,而是开始更加强调算法了。我自己看了一下,也很真实,习题列表里从这一题开始的“成功解题次数”开始出现了一个很大的减少:
感觉很多刷题的人是不是做到这里就做不下去了……
之间其实除了做题之外,对于自己的数据处理里也是用了很多自己写的代码,做的过程中发现一个事情,之前写的很多代码因为只是为了实现功能来对题目给的测试数据有效,实际上测试数据都是比较小的,很多我跑测试数据觉得没问题的代码,一旦面临真实的数据,会出现非常慢的问题。于是我开始思考关于代码速度的问题,拿生物信息学里必须会用到FASTA和FASTQ数据来说,这些数据动不动就是成百万上千行的,很多时候我写的单纯的递归、遍历的方法会导致大量的重复计算,占用大量内存和计算资源的情况下还消耗了很多不必要的时候。这时候就需要很多算法的支持。
这两天做的这道题是关于一个编程中的经典问题——最长递增子序列(Longest Increasing Subsequence,LIS)的。先上题目:
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.
Return: A longest increasing subsequence of π, followed by a longest decreasing subsequence of π.
Sample Dataset
5
5 1 4 2 3
Sample Output
1 2 3
5 4 2
思路
这道题目意思非常明确,就是给定一个有顺序的数组,返回其最长的递增和递减子序列,这里的子序列指的是序列的元素先后关系必须和原数组一致,但是可以不是相连的。
我先想清楚递增的情况吧,拿题目给的这个数组来举例子吧:(8 2 1 6 5 7 4 3 9)。我可以使用遍历的方法:
-
拿到第一个元素8作为开头,找到后面比他大的元素9,组成(8,9),然后9后面没有比它还大的数了,结束;
-
拿到第二个元素2作为开头,找到后面比他大的元素,有很多个(6 5 7 4 3 9),分别把这些数字和2组成新数组,再找这些数字后面比这些数字还大的组成长度为3的新数组……直到最后一个数后面没有比它还大的数。因为这里出现了分支,所以会得到很多个待选数组,我们再选一个长度最长的就结束;
-
拿到第三个元素1作为开头,重复上述的步骤;
-
最终把所有的待选数组都放在一块比长度。
很容易发现这种方法是严重浪费了计算资源的。为什么呢,举个例子,我们用1作为开头,很容易看出有这样一个子序列:(1,6,7,9),但是在下一步在用6作为开头的时候,也会得到(6,7,9)这个数组,但是这个数组明显不可能是我们最终要得到的LIS,因为它在长度上已经输给了前面那个。