题解 | #查找两个字符串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 广东

相关推荐

CrazyBucket:我今天下午也做梦在招聘会上面试一家小厂,给自己气笑了
点赞 评论 收藏
分享
10 2 评论
分享
牛客网
牛客企业服务