题目见下图:
思路:首先要对子序列有一个认识,这里的子序列不是直接截取的,而是从原序列中取出若干字符,而字符间的相对次序不发生改变。这样求得的结果会出现歧义,也可能得到几个满足条件的结果,暂时不考虑。
很容易想到求解此题需要遍历、比较,关键是如何比较?采用“减而治之,分而治之”的思路。
见下图,先考虑序列A和B的最后一个字符是相等的情况,那么最后两个字符就可以凑出一个公共字符(注意:可能A序列的最后一个字符已经和B序列的前某个字符匹配了,那么让A序列的最后一个字符和B序列的最后一个字符匹配,对结果也是没有影响的,得到的公共子序列是一样的)。当A和B的最后一个字符匹配了,那么就可以把最后一个字符拿掉,考虑剩下的字符匹配情况,问题的规模变小了。
下面再考虑A和B的最后一个字符不相等的情况,见下图,这时A序列和B序列的最后一个字符总有一个不能匹配成功,把没有办法匹配成功的字符删掉,再考虑剩下的字符的匹配情况,问题的规律也变小了。
综合上述思路,代码如下,分解,递归:
这里写代码片
这样的求解过程,似然完成了任务,但是算法复杂度呢????对它的分析见下图:
这里出现的问题,也是使用递归求解通常会出现的问题。递归算法的复杂度往往都是指数级别的,就像一棵树一样,不断的进行分裂,而分裂的节点,可能出现大量重复计算的情况,如果规避了重复计算,会大幅降低时间复杂度,但是递归仍然浪费了空间。合适的办法是使用动态规划的思想,把递归问题转成一个迭代求解的问题。结合上述思路,写出代码如下:
这里写代码片
上面的迭代式算法,需要记录每个子问题的局部解,从而导致空间复杂度激增。实际上,这既不现实,亦无必要。可以对算法进一步改进,使得每个子问题只需常数空间,即可保证得到最终的公共最长子序列(而非仅仅是长度)
这里写代码片