首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

算法:最大公共子串

吒吒,你知道怎么求两个字符串的最大公共子串吗?

不知道呀,怎么了,丙丙?

这道题可是在牛客网上热门算法题中成功率最低的一道题之一,好像只有不到10%的正确率哦。但是却一直是考的最多的几道题之一。

啊,那一定很难吧?而且我也要找工作了呢,我还不会这个呀。

一点都不难,我就会好几种解法呢,我来教你吧。

好啊好啊,你真好,丙丙。

吒吒,请听题:

给定两个字符串str1和str2,输出两个字符串的最长公共子串,如果最长公共子串为空,输出-1。

比如:"ab123cd","a123456c",

返回:"123",

备注:1≤|str1|,|str2|≤5000

嗯... ...是不是可以直接用两层嵌套循环遍历啊?

bingo,答对了。这可能是大部分人的第一反应。

我这里有张图你先给你看看吧。

嗯好的。

我明白了!

我们str1取一个i作为索引值,二层循环中str2取j作为索引值。

当str1[i]==str2[j]时,分别使用临时索引m=i,n=j,临时指针m与n,同时往后+1,直到str1[m]与str2[n]不同。

嗯,说的不错,还有呢?

这样,以str[i]为起点的公共最长子串长度为m-i,子串在str1的起点为str[i]。

在遍历中可以取一个maxLength作为最大长度保存值,maxEndIndexInArray1作为子序列的终点在str1的索引值。

当出现某个点超出点长度大于maxLengthn时,则更新maxLength与maxEndIndexInArray1。

嗯,可以可以,孺子可教。

我代码写好了你看看有什么问题吗?

没啥问题,但是务必记得加上下标范围的约束, 避免下标越界, 很多人就失败在这里。

嗯嗯!

这种是暴力解法,虽然思路简单明了。

两层循环,设定m、n分别是字符串长度的话,最大长度maxLenth,时间复杂度为O(m * n * maxLength),空间复杂度是O(1)。

还是可以继续优化的。

我还没有思路额。

你听我说。

对于str1中每个元素,都循环一次str2中所有元素有点浪费。

可以用str2的元素集合构建一个map,key是元素值,value是元素的index。

考虑到可能多个index同样的值,value可以设置为多个index用逗号分隔的字符串。

这样以str1元素为驱动元素的话,只需要在map中找是否有对应的元素,有的话取出他们在str2中的索引列表。

啊,我知道了。

然后针对每个index用上面的图示的双临时指针计算最大子串。

这样的话,时间复杂度为O(m * maxLength),但是空间复杂度由于引入了map,增加为O(n)。

这样好处就可以通过map直接定位元素在str2中位置,不必循环比较str2中元素。

你看我代码。

对!但是其实上面的两种解法都能实现功能,但是有个浪费点在于。

在多轮嵌套循环中,可能有很多重复比较值。

比如在i=1,j=2 时比较了 str1[4] 与 str2[5] 是否相等,而在 i=2,j=3 时可能会再次需要比较 str1[4] 与 str2[5] 是否相同。

对哦,那怎么办才好呢?

你想下,我们是不是可以考虑用一个二维素组dp [m+1] [n+1]来保存 str1[m] 与 str2[n] 是否相同的信息?

如果 str1[m]!=str2[n],dp[m+1] [n+1]=0 标识他们不相等。

如果str1[m]==str2[n],dp[m+1] [n+1]则不为0,标识他们相等。

同时这个点值存放的是dp[m+1] [n+1]点即str1[m]与str2[n]点已经达到的公共子串长度。

那为什么要用dp[m+1] [n+1]保存str1[m],str2[n]是否相等信息,而不用dp[m] [n]?

这是因为如果str1[m]==str2[n],dp[m+1] [n+1]=dp[m] [n]+1,而对于str1中m为0,str2中n为0时,如果用dp[0] [0]来保存,则没有dp[-1] [-1]的元素(数组元素下标最小为0)。

因此都是用dp[m+1] [n+1]来标识str1[m],str2[n]是否相等信息。

哦,好像是这样的哦,可是我还是有点迷糊。

没事儿,我画了张,你对照图看就能明白了。

代码实现如下:

你学会了吗,吒吒?

嗯,我看懂了哦,原来这么容易啊。

那你来总结下几种解法有什么区别吧?

嗯,第三种解法采取了动态规划的思想,解决的问题多数有重叠子问题这个特点,为了减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

这样的话,复杂度就是O(m * n),空间复杂度O(m * n)。

通过用空间换时间,使得字符串1与字符串2每个只是比较了一次!

那他和第一种、第二种解法又有什么不同呢?

他的执行效率优于第一种解法,而和第二种基于map定位的算法各有优劣。

当字符串重复率不高时而长度较长时,第二种算法(hash定位)时间和空间都优于第三种(动态规划)的算法。

当字符串中重复率逐渐升高时,第二种hash的算法效率明显下降,这时候,采用动态规划效率就更高。

不错啊,看来你完全掌握了哦,下次再教你一点新东西吧。

还是丙丙你教的好啊。好啊,下次我们再约!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201210A058NJ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券