题解 | #查找两个字符串a,b中的最长公共子串#

查找两个字符串a,b中的最长公共子串

http://www.nowcoder.com/practice/181a1a71c7574266ad07f9739f791506

题目分析

  1. 题目给出我们两个字符串
  2. 我们需要返回两个字符串的最长公共子串,注意不是子序列

方法一:以长度拓展

  • 实现思路
    • 我们对于一个短一点的字符串s1进行子串截取

    • 我们期待找到一个公共子串,该公共子串的长度为l,l从1到len(s1)遍历

    • 在s1中我们将这个子串提取出来,到s2中进行匹配

    • 如果子串在s2中匹配成功,并且比之前找到的子串长度还要长,则确定当前这个子串为结果,否则之前的子串是结果

    • 最终返回找到的最长公共子串


def solution(s1, s2):
    if len(s1) > len(s2):                        # 较短的字符串用s1表示
        s1, s2 = s2, s1
    mxlen = 0
    for l in range(1, len(s1)):                  # 规定一个子串长度,找找s1和s2中是否有符合的相同子串
        for i in range(0, len(s1)-l+1):          # 遍历s1子串起点进行尝试
            sub = s1[i:i+l]                      # 切分子串
            if sub in s2 and l > mxlen:          # 搜索是否存在且是否需要更新
                mxlen = l
                res = sub
    print(res)
    
    return

while True:
    try:
        s1 = input()
        s2 = input()
        solution(s1, s2)
    except:
        break

复杂度分析

  • 时间复杂度:O(mn2)O(mn^2),其中s1长为m,s2长为n,代码中可见的部分有双重循环,在in方法中又又O(n)O(n)的时间代价,总计O(n3)O(n^3)时间代价
  • 空间复杂度:O(1)O(1),只引入了一些变量级别的常数空间开销

方法二:双指针+剪枝

  • 实现思路
    • 我们这次通过先确定一个子串首,再遍历确定子串尾的方式进行切分
    • 切分完成后将这个子串在s2中进行查找,如果找到公共子串,则判断是否当前的更长,如果更长则计入mxlen中,并且更新结果子串
    • 如果我们已经确定了一定长度的子串,则我们之后在双指针确定子串首尾的时候直接在这个长度基础上寻找,因此我们甚至不用判断 j - i > mxlen 这一步骤

alt



def solution(s1, s2):
    if len(s1) > len(s2):                        # 较短的字符串用s1表示
        s1, s2 = s2, s1
    mxlen = 0
    for i in range(len(s1)):                     # 找一个子串起点
        for j in range(i+1+mxlen, len(s1) + 1):  # 找一个子串终点
            sub = s1[i:j]                        # 截取子串
            if sub in s2 :                       # 子串是否在s2中
                res = sub
                mxlen = j - i
                continue
    print(res)
    
    return

while True:
    try:
        s1 = input()
        s2 = input()
        solution(s1, s2)
    except:
        break

复杂度分析

  • 时间复杂度:O(mn2)O(mn^2),虽然最差结果时间代价还是三次方,但是中间过程可以省去很多不必要的遍历和查找
  • 空间复杂度:O(1)O(1),只引入了一些变量级别的常数空间开销
全部评论
第一个没有考虑到短的子串就是最长公共子串的情况
2 回复 分享
发布于 2023-02-03 18:13 山东
第二个方法在第二层循环最后加一个break效率会更高
点赞 回复 分享
发布于 2022-08-31 15:58 北京
思路清晰,赞
点赞 回复 分享
发布于 2022-09-26 15:20 广东
第二个方法如果遇到长度一样的字串那会不会不会输出第一个?
点赞 回复 分享
发布于 2022-10-26 22:05 广东
第一种方法,方法最后这里为什么要先print(res)然后return?直接return res为啥不行呢?有哪位大佬帮解答一下
点赞 回复 分享
发布于 2023-02-23 15:04 山东
for j in range(i+1+mxlen, len(s1) + 1)中i+1+mxlen, 为什么还要加1呢?
点赞 回复 分享
发布于 2023-02-23 15:45 山东
第一种if sub in s2 and l > mxlen的l > mxlen表示什么?
点赞 回复 分享
发布于 2023-05-26 20:01 浙江
为啥第一种方法不算in的时候时间复杂度是mn^2?
点赞 回复 分享
发布于 2023-10-09 23:07 广东
从前往后遍历,同一个长度的公共子串只会记录一次,这次也是这个子串出现得最早的一次,也就是第一次出现的最长公共子串,至于这个串后面有没有重复出现过不知道也不关心
点赞 回复 分享
发布于 2023-10-09 23:19 广东

相关推荐

群星之怒:1.照片可以换更好一点的,可以适量P图,带一些发型,遮住额头,最好穿的正式一点,可以适当P图。2.内容太少。建议添加的:求职意向(随着投递岗位动态更改);项目经历(内容太少了建议添加一些说明,技术栈:用到了什么技术,还有你是怎么实现的,比如如何确保数据传输稳定的,角色注册用到了什么技术等等。)项目经历是大头,没有实习是硬伤,如果项目经理不突出的话基本很难过简历筛。3.有些内容不必要,比如自我评价,校内实践。如果实践和工作无关千万别写,不如多丰富丰富项目。4.排版建议:建议排版是先基础信息,然后教育背景(要突出和工作相关的课程),然后专业技能(一定要简短,不要长篇大论,写你会什么,会的程度就可以),然后是项目经历(一定要详细,占整个简历一定要超过一半,甚至超过百分之70都可以)。最后如果有一部分空白的话可以填补上校内获得的专业相关的奖项,没有就写点校园经历和自我评价。5.技术一定要够硬,禁得住拷打。还有作息尽量保证正常,不要太焦虑。我24双非本科还是非科班,秋招春招各找了一段实习结果都没有转正,当时都想噶了,最后6月份在校的尾巴也找到一份工作干到现在,找工作有时很看运气的不要急着自我否定。 加油
点赞 评论 收藏
分享
03-03 10:35
3d人士会梦见住进比弗利山庄吗:这四个项目属于是初学者的玩具了。不知道面试官咋问,而且双非本搞算法除了9,还是保守至少c9
点赞 评论 收藏
分享
评论
11
2
分享

创作者周榜

更多
牛客网
牛客企业服务