一、题目描述
题目:最长重复子串
难度:困难
描述:给你一个字符串 s ,考虑其所有 重复子串 :即,s 的连续子串,在 s 中出现 2 次或更多次。这些出现之间可能存在重叠。
返回 任意一个 可能具有最长长度的重复子串。如果 s 不含重复子串,那么答案为 “” 。
示例1
输入:s = “banana”
输出:“ana”
示例2
输入:s = “abcd”
输出:""
二、题目解析
本题看似简单,实则十分烧脑,题目中让我们找到最长的重复子串,而题目的特点就在于重叠,先让我们通过下图来了解一下重叠的含义:
根据上图所示,子字符串1使用了前三个字符,子字符串2使用了后三个字符,中间两个字符被重复使用,这种情况就称之为重叠。
了解了重叠之后解题主旨就变成了一个判断后续字符串中是否含有已知字符串的问题,只要我们能够找到所有的已知字符串,再从中找到最长的那一个就轻而易举了。
主要思路
定义左右双指针,将双指针的区域视为滑窗,最开始滑窗中只包含字符串中最左侧的元素,判断该元素在剩余的子串中时候存在,若存在则将右侧指针右移一位,使得滑窗中包含两个元素,继续判断,若仍然存在则继续执行上述操作,图示如下:
如图所示,黄色表示滑窗,绿色表示后续子串中具有和滑窗子串相同的子串,当滑动过程中匹配不到相同子串时,则将滑窗左侧右移一位移除头部元素。图示如下:
接下来我们重复上述过程并不断保留满足条件的最长子串内容即可。
注:匹配相同子串的时候通常会使用KMP算法(Python中提供的in方法就使用了该算法)
三、解题代码
解法(一)
按照解析中的方法进行代码编写如下:
class Solution: def longestDupSubstring(self, s: str) -> str: # 左指针 left = 0 # 右指针 right = 1 res = "" n = len(s) while right < n: # 判断后续字符串中是否含有判断字符串 if s[left:right] in s[left + 1:]: if right - left > len(res): res = s[left:right] # 字符串右侧右移一位 right += 1 continue # 字符串左侧右移 left += 1 if left == right: right += 1 return res