LCS(最长公共子串 longest common subsequence)一般都会采用动态规划的算法来实现,算法的时间复杂度大概是O(x2), 另外需要一个x2的额外空间, 这个算法这里我不做说明,给个讲得不错的教程地址
这边博文里我将给出一个不采用动态规划的算法,并且时间复杂度和动态规划算法相同,还不会使用到额外的空间,空间复杂度为O(0)。
思路:
假设存在两个字符串l和r, 并且strlen(l) <= strlen(r),
将l字符串想象成一辆车,
将r字符串想象成公路,
车从公路的左边开到右边,
从左边-->右边的这个过程中字符串l和r中相同的部分总会有重合的情况, 统计出最大的串的长度。
--->开始
Car(字符串l) ---------------
Road(字符串r) ----------------------------------------------------
Car(字符串l) ---------------(终点)
在移动的任何一步里都可以检测到子串重合的情况。 比如在移动的过程中如下图,在这个状态发现红色下划线那部分子串相同, 检测这个状态只要时间复杂度O(N), N为l字符串的长度。
---------------
----------------------------------------------------
代码如下:
int lcs(const char *s1, int n1, const char *s2, int n2) { int i, steps, ln, rn; int max; int moves; const char *l; const char *r; if (n1 < n2) { l = s1; r = s2; ln = n1; rn = n2; } else { l = s2; r = s1; ln = n2; rn = n1; } max = 0; for (steps = 0; steps < ln + rn - 1; ++steps) { moves = 0; //检测每次移动后子串重合的情况, 这里可以优化的, 我这里只是把意思表示出来, 忽略一些细节:-) for (i = steps; i < steps + ln; ++i) { if (i < ln - 1) continue; if (i > (ln + rn - 1) - 1) { max = moves > max ? moves : max; break; } if (l[i - steps] == r[i - ln + 1]) { ++moves; max = moves > max ? moves : max; } else { max = moves > max ? moves : max; moves = 0; } } } return max; }