问题描述
前几日有粉丝问了这样一个问题:
经过小编思考过后,特意写了此文来为该粉丝解答疑惑。
解决方案
首先抓取问题的关键点,一是“最长”,二是“公共”。然后再看问题都是在字符串中操作,所以小编首先想到的就是对字符串进行一系列切片操作。具体怎么实施,还得回到问题要求来。首先处理“最长问题”,既然是找最长,我们不妨就从最长子串开始依次递减一个字符进行比对。再结合“公共”来看,可知公共子串必定由给定字符串集中最短字符串决定,所以小编想到了先选取出给定字符串集中最短的字符串进行切片操作。
如何选最短的字符串小编就不多说了,我们直接来看如何切片。前面已经说了,要从最长子串也就是本身开始依次递减一个字符进行比对。这里我们用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) #将输入的每行字符串加入列表lis ss1 = 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
实习编辑 | 王文星
责 编 | 江来洪
where2go 团队
微信号:算法与编程之美
长按识别二维码关注我们!
温馨提示:点击页面右下角“写留言”发表评论,期待您的参与!期待您的转发!