2019/10/15 02-求最大公共子串

在这里插入图片描述
矩阵算法效率高,截取的方法就效率比较低下

矩阵,假设有s1,s2两个字符串
s1=‘abcdefg’ s2=‘defabcd’
一看abcd就是公共子串,最长的abcd
让s2的每一个元素,去分别和s1的每一个元素比较,相同就是1,不同就是0,有下面的矩阵,右边可以看作0和1的矩阵

在这里插入图片描述在这里插入图片描述
第一个d开始找,找到相同的就是1,0001000
在这里插入图片描述
矩阵的第二行,e
在这里插入图片描述
在这里插入图片描述
f接下去找,倒数第二个除个1,其他都是0
在这里插入图片描述
在这里插入图片描述
找a
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
c
在这里插入图片描述
在这里插入图片描述

现在是拿s2的元素一个一个到s1里面去比较,得到这样的矩阵
3个1,和4个1,

在这里插入图片描述
找到谁最长,就要知道是谁
在这里插入图片描述
0123取出来,不就是abcd
在这里插入图片描述
我们取的时候就用切片取,把3取上就需要用4,因为前包后不包
但是刚才扫描一遍,眼睛是看出来了谁最长,但是算法没看出来,还得遍历 一遍(如何知道谁最长)

在这里插入图片描述
如果上面是m,下面是n,遍历过程就是mn的问题,因为这是一个mn的矩阵
在这里插入图片描述
如果这个矩阵用二位数组i和j来表示的话,i和j对上一个来讲,刚好差1,下一个是x轴+1,y轴+1,上一个就是x轴-1,y轴-1,对i和j来讲就是+1和-1的问题
如果下面看成二维数组,坐标分别加1就得到这个位置了

在这里插入图片描述
需要做点改变,这么思考 在这里插入图片描述在这里插入图片描述
第一行,0001000,如歌索引定位(3,0)
在这里插入图片描述
第二行就是(4,1)处是1,能否判断(3,0)的位置是否也是1,为1就把(3,0)处加1,
在这里插入图片描述
**就转变成这样了,每碰到个1就回头看一眼,如果发现也是1,就加,如果不是1,就不能加,因为是从你开始的,不能加它, **
在这里插入图片描述
如果是1说明是从它开始的,如果是0就不能加了,不是0就可以加,这种回头加法,(我先找你,你上面还找,再往后加,再往后加,就是典型的递归问题(这种思路是解决问题了,但是用递归效率低)
在这里插入图片描述
矩阵的第一行,第二行,矩阵的下一行算上一行能算出来,二维的矩阵应该都写过,二维矩阵的上一个元素怎么得到,而且是斜上的,i和j -1就完了,值是几就看看索引里面对应的是不是0就完了

如果发现不是(下面的值)0就继续向上找,用到递归了(找上一个再找上一个),非常麻烦,这是逆推的方式,能否把递归避免掉在这里插入图片描述
能不能反过来,上面的1,因为是第一行没辙,下面第二行的出现1回头看一眼,如果上面也是1,把自己变成+1=2
在这里插入图片描述
第三行回头看一眼,如果别人是2,它就是3
在这里插入图片描述
最后得到这样的
在这里插入图片描述
在这里插入图片描述
这是依赖于上一次的计算结果,最大数的索引和最大数是多少都得记得,有了最大数就知道了下回跟谁比,你比它大就把索引更新掉,同时把最大数更新掉
有了最大数和最大数对应的索引,从哪开始结束应该可以知道
(其实最大数告诉你有多长了,因为最大数已经告诉你有多长了,你当前索引是几,你就知道自己长度起点在哪了)

在这里插入图片描述
3+1-4=0
4的索引就是i,
区间就是[0:i+1]
索引+1就是结束的东西,用这种方式就可以找到你想要的东西

在这里插入图片描述
有两个string,想要计算最长子串,1个4个字符,1个有10个字符
最长就也不超过短的
假定最短的是str1,如果str2比str1还短,就把两个换一下,假定str1最短

在这里插入图片描述
最短字符串长度
在这里插入图片描述
矩阵有两种方式,一种是append出来,一种是一把创建好
martix矩阵
纵向的控制由长度长的决定

在这里插入图片描述
先来看一下
在这里插入图片描述在这里插入图片描述
*3.4,s2找4次,每一次迭代三下在这里插入图片描述
这样的情况,修改了里面其中一个,并不会对全部都进行修改,所以列表解析式可以解决问题的
在这里插入图片描述
0是常量,常量不是引用类型,不会出现问题,每次做循环都重新创建,里面每一个都是不同的
在这里插入图片描述

为什么先要创建矩阵,因为字符串是固定长度,有了s1和s2,你的矩阵大小就知道的很清楚,如果现在的数字给了多少个不能固定,就需要用append的方式,
但是现在不用,因为长度我们知道
横向是s1的长度,纵向是跟s2有关

在这里插入图片描述
从str2里拿一个字符到str1里面去找
在这里插入图片描述
当什么时候应该怎么样,xy,标记为1,不等应该不操作,里面已经有0了
如果x!=y,什么都不做pass
否则就是x
y的情况

在这里插入图片描述
如果要找公共子串就要在边界上看了,边界上标记1就一定是个开始,
边界上的标记有个特点
首先标记的数一定是1
在这里插入图片描述
**现在需要描述边界,i0或者j0
就需要在矩阵matrix,索引里做文章了,标记成1即可
现在i走到0上,j 标注为1
如果不是,代表不在边界上,就需要回头看一眼,查看前面的值是几,不在边界上放心的i-1,j-1
如果这个数pre >0,说明已经开始,但是不是从它开始就不清楚
**在这里插入图片描述
假如你现在到3的地方,准备写3,就看原来是多少,看到是2,就>0,大于0说明至少是公共子串的一部分,但是不一定是开头,开头是1
在这里插入图片描述
如果大于0,就把当前的值,+1,如果上面的值大于1就需要+1的,斜着加在这里插入图片描述
打印一下标注过的
在这里插入图片描述在这里插入图片描述
现在还需要判断哪个值比较大
假定最大值max是0
最大索引值xindex是0

在这里插入图片描述
在边界上等于1要做一些工作,是可以得到最大值的
就需要做完这个事,看看是否是最大值
最大值就赋值
最大的索引也赋值

在这里插入图片描述
再次打印
在这里插入图片描述
4最大值,索引是3,长度最长是4
得到这个后,把这一段取出来即可

在这里插入图片描述
起始部分,就需要索引往左回,我们现在都是用的s1,在s1上标记索引的状态的
在这里插入图片描述
到什么时候结束,索引3+1即可
在这里插入图片描述
我们是拿s2的字符在s1上去标状态,所以这里的索引都是s1的,使用return也可以
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
更多的思考方式。字符串都是连续的字符,
从s1中依次取一个字符,到s2查找,查看是否能找到子串,
如果没有一个字符在s2中找到,说明就没有公共子串,直接退出,如果找到了至少一个公共子串,则很有可能还有更长的公共子串,可以进入下一轮。
第二轮(找到了,下面可能有更长的,但是有没有试试再说,一个字符找到了,可以2个2个来)
s1中取连续的2个字符,在s2中查找,看看能否找到公共的子串,如果没找到,说明最大公共子串就是上一轮的随便的哪一个就行了。如果找到至少一个,则说明公共子串可能还可以更长一些。可以进入下一轮。

在这里插入图片描述
举个例子 s1 abc1 abcde
abc找abcde公共子串
第一次,取第一个字符a找,发现有
第二次,取2个字符,ab找,发现有
第三次,取三个字符,abc找,发现于
第四次,abc1找,没找到,说明只找到一个公共子串,现在又一个比较长,叫abc
找不到用上一轮,找到继续探测下一轮的,这一轮找到,下一轮探测不到了,说明这一轮才是最长的,

在这里插入图片描述
找公共子串,就需要先把两个字符串里面最短的那个当作最长公共子串,
假设abcdef是最长公共子串,做个长度比较,找到最短的字符串,当作最长公共子串
第一步,把全长到里面找,abcdef到abcdefg里面找,找到了很好,没找到往下切
第二步,abcde ,bcdef,这两个分别到里面去找
(那么能否把你要用的字符串先切出来)

试试写下这个思路的代码
首先拿短的字符串当作最长的公共子串

在这里插入图片描述
第一次拿全场,需要有一个start,和控制一个长度的,sublen子串长度
start也需要递增,0,1
substr就是测试的子串

在这里插入图片描述
一开始length是3,sublen ,0,1,2
start如果要使用就是0开始 start+sublen=3【0:3】正好前包后不包
在这里插入图片描述
试试能不能用
在这里插入图片描述在这里插入图片描述
说明找的对的,现在是倒着走的,只要有个子串找到了,还有没有必要继续

现在拿到子串,如果这个子串在什么里面去找这个子串,则如何
用find方法在里面找substr,找不到就是-1,如果大于-1,如果找到了就没有必须继续计算了,把substr返回回来就行
在这里插入图片描述在这里插入图片描述

思路2 :
是假设s1,s2两个字符串,s1短一些。
既然是求最大子串,最长子串不会超过最短的字符串,先把s1全长的作为子串。
在s2中搜索,是否返回正常的index,正常就找到了最长子串。
没有找到,把s1按照length-1取多个子串。
在s2中搜索,是否能返回正常的index。(如果能返回不是-1的index,就代表找到了,找到了就可以立即返回子串)
注意:
不要把s1的所有子串生成,用不了,也不要从最短开始,因为题目要 最长的。
但是也要注意,万一他们的公共子串就只有一个字符,或者很少字符的,思路一就会占优势。

在这里插入图片描述
找最初始的算,找到规律就可以了在这里插入图片描述
推荐使用矩阵算法,很简单
在这里插入图片描述
能否把这条省略 在这里插入图片描述
边界一定是1,在非边界的左斜上去看看,一定是大于0的,也可能真是0,如果是0,就是当下(你不是边界,从你开始,它是0,你拿它的值+1就是1,m[i-1][j-1】+1=1,
现在不在边界,左斜上去看,数字是2,自己变成3)

也就是左斜上去看,它是0,代表从你开始,拿数字+1即可,如果左斜上的数字是2,就+1,现在加一下就是3,因为是一条线下来的
在这里插入图片描述
用矩阵算法是比较简单的,这里用append也可以,但是用一开始开辟也可以
在这里插入图片描述
面试,公共子串算是比较难的,递归主要学会一种模式,往往会问斐波那契数列,递归(效率问题,用缓存是最简单,如果能借用上一次计算结果,
递归深度限制 limit cpython1000)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值