字符串-最长公共子串(两个,多个)

  • Post author:
  • Post category:其他


关于暴力解和动规说的最好的

https://www.cnblogs.com/ider/p/longest-common-substring-problem-optimization.html

空间复杂度 O(1) 还是左神的p225说的好。其实也没什么意思orz!

问题:有两个字符串str1和str2,求出两个字符串中最长公共子串长度。

暴力解:

1)把str1和str2的所有子串都找到,然后挨个比较

时间复杂度:

假设两个字符串str1和str2的长度分别为x和y,则字符串的子串个数分别为

n1 = x + (x-1) + … + 1 = x(x-1) / 2

n2 = y + (y-1) + … + 1 = y(y-1) / 2

所以,暴力求解法下,对比两个子串是否相等,时间复杂度为O(x^2*y^2),即O(n^4)。

2)稍微把暴力解优化一点

a)优化方法1

遍历str1的每一个子串a,然后str2.find(a)==string::npos 看str2里面有无对应的子串,因为find用的是kmp,find的复杂度是y,所以总的复杂度是O(x^2*y),即O(n^3)

b)优化方法2

不用str.find 也能做到O(n^3)

不是遍历str1的每一个子串,而是把str1中以str1【i】为开头,str1【str1.len()-1】为结尾的子串,跟str2中以str2【j】为开头,str2【str2.len()-1】为结尾的子串,依次比较,找到两个字符串的最长公共前缀,复杂度依旧是O(n^3)。

3)动规 时间复杂度 O(n^2)

状态转移方程:

假设,两个字符串分别为

A = a1, a2, …, ax

B = b1, b2, …, by

我们定义dp[i][j]的含义是:必须把A[i-1]和B【j-1】当作公共子串最后一个字符的情况下,公共子串最长能有多长。

常规动规思想:

https://blog.csdn.net/ten_sory/article/details/79857531

另一种角度:

https://blog.csdn.net/qq_25800311/article/details/81607168

class LongestSubstring {
public:
    int findLongest(string A, int n, string B, int m) {
		if(n<=0 || m<=0) return 0;
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));
		int res = 0;
		//dp【i】【j】 代表的是A[i-1] B[j-1]
		for(int i=1;i<=n;++i){
			for(int j=1;j<=m;++j){
				if(A[i-1]==B[j-1]){
					dp[i][j]=dp[i-1][j-1]+1;
					res = max(dp[i][j],res);
				}
			}
		}
		
		return res;
    }
};

假如问题是多个字符串呢?

自然dp数组的维度就是n维的,时间复杂度也是O(n^n),实际中自然不可能用这种方法的,那就是用后缀数组做,不过这逼玩意属实太难,假如面试碰到,跟他bb一下,就ok了

把n个字符串的所有后缀,排序,假如n个字符串的总长度是K,那么后缀的个数是K,而排序假如用倍增算法+基数排序,那时间复杂度是O(KlogK),即使用快排,假如字符串是随机的,那其实也就是O(KlogK)

最坏的情况: 快排每个后缀(n log n),但是这是字符串,所以比较任意两个后缀的复杂度其实是O(n),这样一来就是接近O(n^2 log n)的复杂度,但是其实,假如是随机的字符串,比较任意两个后缀的平均复杂度应该是O(1),因为一共就那么几个字符,比不了几个字符就判断出大小了。

然后还有几个重要的性质:

1)任意1个子串都是某个后缀的前缀

2)任意2个后缀(i,j)之间的最长公共前缀,都是这一段相邻后缀之间的最长公共前缀的最小值,

即  LCP(i,j)=min(i<k<=j)(LCP(k-1,k))

而求相邻两个最长公共前缀(即,里面的height数组)又有个优化,可以做到O(N)

搞出了这些之后,对于n个字符串的最长公共前缀,是后缀数组中相邻n项(得是分别来自n个不同字符串)的

最大公共前缀,


最后的复杂度是

O(K* logK)

n个字符串的  具体的可以看看

https://www.xuebuyuan.com/3226411.html

后缀数组: 粗暴介绍

https://www.xuebuyuan.com/274781.html

性质2的证明

https://blog.csdn.net/qq_36172410/article/details/89816078

比较图形化的介绍:

https://www.cnblogs.com/jinkun113/p/4743694.html


https://www.cnblogs.com/victorique/p/8480093.html

最后贴的论文 很棒!

https://blog.csdn.net/zy799894671/article/details/7761171



版权声明:本文为speargod原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。