前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >答粉丝问|求给定字符串中最长公共子串

答粉丝问|求给定字符串中最长公共子串

作者头像
算法与编程之美
发布2019-12-24 12:33:02
6200
发布2019-12-24 12:33:02
举报
文章被收录于专栏:算法与编程之美

问题描述

前几日有粉丝问了这样一个问题:

经过小编思考过后,特意写了此文来为该粉丝解答疑惑。

解决方案

首先抓取问题的关键点,一是“最长”,二是“公共”。然后再看问题都是在字符串中操作,所以小编首先想到的就是对字符串进行一系列切片操作。具体怎么实施,还得回到问题要求来。首先处理“最长问题”,既然是找最长,我们不妨就从最长子串开始依次递减一个字符进行比对。再结合“公共”来看,可知公共子串必定由给定字符串集中最短字符串决定,所以小编想到了先选取出给定字符串集中最短的字符串进行切片操作。

如何选最短的字符串小编就不多说了,我们直接来看如何切片。前面已经说了,要从最长子串也就是本身开始依次递减一个字符进行比对。这里我们用abcde来举例,第一个子串肯定是abcde,然后判断其他几个字符串中是否都含有abcde这个子串,如果是就输出,这自然就是最长的公共子串了,如果不是,那就进入下一个循环。第二个子串也就是四个字符的abcd,比对方法同上,同样四个字符的还有bcde,再三个字符的,abc,bcd,cde,两个字符的,ab,bc,cd,de,一个字符的,a,b,c,d,e。具体过程就是这样。

那这个过程有什么规律呢?这自然是有的,小编发现每一个长度的字符串个数n与原字符串长度L和子串长度l有n=L-l+1的关系,找出这个关系后就可以对循环定次数了,同样切片的下标自然也是可以运用这个关系的。

分析完问题后,整理下思路,将其转化为程序语言。

代码示例:

N = int(input()) #输入一个整数,代表你下面要输的行数lis = []lis1 = [] #定义两个空列表备用for i in range(N): ss = input() #输入需要比较的字符串 lis.append(ss) #将输入的每行字符串加入列表lisss1 = lis[0]for a in lis: if len(a)<len(ss1): ss1 = a #用for循环找出列表lis中最短字符串,并求其长度,然后从列表lis中删除l = len(ss1)lis.remove(ss1)num2 = 0 #定义一个计数变量for n in range(l): #以最短字符串长度来定循环次数,遍历每一种子字符串长度的情况 for b in range(n+1): #遍历一种长度的每一种子字符串 num1 = 0 for m in lis: #遍历lis中的每一个字符串 if ss1[b:l-n+b] in m and ss1[b:l-n+b] not in lis1: #用切片依次切出一种长度的每种子字符串 num1 += 1 #若该子字符串在字符串m中,并且不与前面切出过的子字符串相同计数器就加1 if num1 == N-1: #如果计数器的值与lis的长度及N-1相等,说明该子字符串在lis的每一个字符串中 num2 = 1 #找到一个最长公共子字符串计数器num2就等于1 lis1.append(ss1[b:l-n+b]) #满足的条件的子字符串加到列表lis1中 print(ss1[b:l-n+b],end=' ') #输出所有相同长度且都为最长公共子字符串的子字符串 if num2 == 1: break #如果循环完一种长度的所有种子字符串且找到了最长公共子字符串,循环终止

结语

小编刚拿到这个问题的时候,以为很简单,随便做了一下,在检测时才发现漏洞百出,最后也是在纸上分析了切片的规律,找出了其中的逻辑关系,才得以解决这个问题,所以小编想告诉大家,遇到问题还是先分析分析,最好是在纸上画一画。

END

实习编辑 | 王文星

责 编 | 江来洪

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法与编程之美 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档