无论题目怎么样,始终有一个宗旨,那就是一步一步接近结果,最后你会发现一个最终最优化的解题思路,如果你直接看最优解题思路,会比较突兀,理解起来不是很好,一步一步想,会感觉水到渠成,最后你会发现任何已有的算法都基于一个很朴素的想法。
问题描述
给定两个字符串,求出字符串中最长匹配的公共字符串,而且可以不用相连,比如"abcdef"和"abfce",我们可以找到“abce”是最长的公共字符串
问题分解
其实上述的问题,可以分解成两个子问题
(1)首先,找出相连的公共子字符串,比如"abcdef"和"abfce",结果就是"ab"
(2)其次,再考虑这个问题,即不相连的公共字符串
对第一个子问题的分析
一拿到这个问题,最暴力的方法就是穷举,再一一比较字符串。
再想想,我们就可以发现字符串的比较,其实就是比较字符。为了避免重复的比较,我们用一个二维数组记录之前的比较结果。
下面以"abfcd", "abcdef"为例,加以说明。
[ab, ab]而言,对于的是2,也就是说最长公共字串是2.
[abf, ab]而言,在3*2的矩阵中,最大的数字也是2,那就意味着最长公共长度也是2.
比较字符是否相同,若两字符相同,则对于的数字是斜对角的数字加一。
至于结果的打印,我们可以通过记录下最大的长度,再找出所有最大的长度,就可以打印所有的结果了。
这样就把穷举简化成时间复杂度为o(n*m)的问题,其实这就是动态规划,其本质就是用空间记录之前的比较结果,以此来达到优化时间复杂度的目的。
该算法空间负责度为o(n*m),我们还可以进行再一步优化为o(n)的时间复杂度,其思路跟背包问题相似,至于是逆序,顺序都可以,但是为了打印所有结果的话,必须得用逆序实现。
1 //find the successive common substring 2 #include <stdio.h> 3 #include <iostream> 4 using namespace std; 5 #define N 100 6 int a[N + 5][N + 5]; 7 char s1[N + 5] = "abfcd"; 8 char s2[N + 5] = "abcdef"; 9 void main() 10 { 11 int i, j, k, len1, len2, max, count; 12 //---------------o(n * n) 13 max = 0; 14 for (i = 0; s1[i] != '