问题是给定字符串x和y,求出两个当中最长的公共子序列。比如x=abcdef y=acefg,那么他们的最长公共子序列就是acef。就是求x的所有可能的子字符串与y所有的子字符串匹配,如果相同,那么就是一个公共子序列,然后求最长的一个。
建议观看上面的公开课,讲的非常好。本文思路是根据上面的公开课总结实践的。
一
我们先看看求一个字符串的所有子序列,有什么规律。比如给定一个字符串abc,那么有多少子序列呢?a b c ab ac bc abc还有一个空,就是2^3。按照上面公开课讲的非常通俗易懂,就是字符串一共有n个字符,那么每一位的字符都有两个状态----0-不是子序列的一员 1-是子序列的一员。那么总共的种类就是2^n种。这是最坏的情况,字符串中没有相同的字符,如果有,结果会比这个少。但是计算就是这么计算的。
了解了上面,那么我们进一步判断,如果给定一个x的子序列x1,那么怎么判断y中是否含有呢?简单的方法就是从x1的起始位置和y的起始位置开始判断,如果相同,每个索引加一,直到x1/y的字符串判断结束。如果不匹配,那么y索引加一,再从x1的开头开始计算。
这种是穷举法,肯定能得到结果,但是时间和空间都是最差的。我们先实现看看(穷举法排列组合可以参考排列组合)
struct MNODE { string substr; MNODE* pnext; MNODE() { pnext = nullptr; } }; MNODE* msubstr(string& srcstr, int index, int sublen) { MNODE* tmpp = nullptr; MNODE* prep = nullptr; if (index >= sublen && sublen > 0) { if (sublen == 1) { for (int i = 0; i < index; i++) { MNODE* ftpn = nullptr; if (tmpp == nullptr) { tmpp = new MNODE; prep = tmpp; ftpn = tmpp; } else { ftpn = new MNODE; prep->pnext = ftpn; prep = ftpn; } ftpn->substr = srcstr[i]; } } else if (sublen > 1) { MNODE* nsub = msubstr(srcstr, index - 1, sublen - 1); tmpp = nsub; while (nsub != nullptr)