最长重复子串(Longest Repeated Substring)
字数 1245 2025-11-12 11:17:50

最长重复子串(Longest Repeated Substring)

题目描述
给定一个字符串s,找到其中最长的重复子串。重复子串是指在字符串中至少出现两次(出现位置不能重叠)的连续子串。如果有多个这样的子串,返回任意一个即可。

解题过程

这个问题可以用动态规划高效解决。让我们循序渐进地分析:

1. 问题分析

  • 我们需要找到在字符串s中出现至少两次的连续子串
  • 子串的出现位置不能重叠
  • 目标是找到最长的这样的子串

2. 动态规划定义
定义dp[i][j]为以第i个字符和第j个字符结尾的最长公共子串的长度,其中i < j。

3. 状态转移方程

  • 如果s[i-1] == s[j-1],那么dp[i][j] = dp[i-1][j-1] + 1
  • 否则,dp[i][j] = 0

4. 边界条件

  • 当i = 0或j = 0时,dp[i][j] = 0
  • 当i = j时,我们不考虑这种情况,因为同一个位置不能算作重复

5. 算法步骤
让我们通过一个例子来理解:s = "ababc"

步骤1:初始化dp表

   - a b a b c
- 0 0 0 0 0 0
a 0
b 0
a 0  
b 0
c 0

步骤2:填充dp表

  • 比较s[0]和s[1]: 'a' ≠ 'b' → dp[1][2] = 0

  • 比较s[0]和s[2]: 'a' = 'a' → dp[1][3] = dp[0][2] + 1 = 1

  • 比较s[0]和s[3]: 'a' ≠ 'b' → dp[1][4] = 0

  • 比较s[0]和s[4]: 'a' ≠ 'c' → dp[1][5] = 0

  • 比较s[1]和s[2]: 'b' ≠ 'a' → dp[2][3] = 0

  • 比较s[1]和s[3]: 'b' = 'b' → dp[2][4] = dp[1][3] + 1 = 1 + 1 = 2

  • 比较s[1]和s[4]: 'b' ≠ 'c' → dp[2][5] = 0

  • 比较s[2]和s[3]: 'a' ≠ 'b' → dp[3][4] = 0

  • 比较s[2]和s[4]: 'a' ≠ 'c' → dp[3][5] = 0

  • 比较s[3]和s[4]: 'b' ≠ 'c' → dp[4][5] = 0

6. 寻找结果
在填充dp表的过程中,我们记录最大值和对应的位置:

  • 最大值为2,出现在dp[2][4] = 2
  • 这意味着以位置1和位置3结尾有长度为2的重复子串
  • 子串是s[1-2+1:1+1] = s[0:2] = "ab"

7. 复杂度分析

  • 时间复杂度:O(n²),其中n是字符串长度
  • 空间复杂度:O(n²)

8. 优化
我们可以优化空间复杂度到O(n),因为每次只需要前一行的信息:

def longest_repeated_substring(s):
    n = len(s)
    max_length = 0
    end_pos = 0
    
    # 使用两行来优化空间
    prev = [0] * (n + 1)
    curr = [0] * (n + 1)
    
    for i in range(1, n + 1):
        for j in range(i + 1, n + 1):
            if s[i-1] == s[j-1]:
                curr[j] = prev[j-1] + 1
                if curr[j] > max_length:
                    max_length = curr[j]
                    end_pos = i - 1
            else:
                curr[j] = 0
        prev, curr = curr, prev
    
    if max_length > 0:
        return s[end_pos - max_length + 1: end_pos + 1]
    return ""

9. 验证
对于s = "ababc":

  • 最长重复子串是"ab"或"ba"
  • 算法正确找到了"ab"

这个解法通过动态规划高效地找到了最长的重复子串,既保证了正确性又具有良好的时间复杂度。

最长重复子串(Longest Repeated Substring) 题目描述 给定一个字符串s,找到其中最长的重复子串。重复子串是指在字符串中至少出现两次(出现位置不能重叠)的连续子串。如果有多个这样的子串,返回任意一个即可。 解题过程 这个问题可以用动态规划高效解决。让我们循序渐进地分析: 1. 问题分析 我们需要找到在字符串s中出现至少两次的连续子串 子串的出现位置不能重叠 目标是找到最长的这样的子串 2. 动态规划定义 定义dp[ i][ j]为以第i个字符和第j个字符结尾的最长公共子串的长度,其中i < j。 3. 状态转移方程 如果s[ i-1] == s[ j-1],那么dp[ i][ j] = dp[ i-1][ j-1 ] + 1 否则,dp[ i][ j ] = 0 4. 边界条件 当i = 0或j = 0时,dp[ i][ j ] = 0 当i = j时,我们不考虑这种情况,因为同一个位置不能算作重复 5. 算法步骤 让我们通过一个例子来理解:s = "ababc" 步骤1:初始化dp表 步骤2:填充dp表 比较s[ 0]和s[ 1]: 'a' ≠ 'b' → dp[ 1][ 2 ] = 0 比较s[ 0]和s[ 2]: 'a' = 'a' → dp[ 1][ 3] = dp[ 0][ 2 ] + 1 = 1 比较s[ 0]和s[ 3]: 'a' ≠ 'b' → dp[ 1][ 4 ] = 0 比较s[ 0]和s[ 4]: 'a' ≠ 'c' → dp[ 1][ 5 ] = 0 比较s[ 1]和s[ 2]: 'b' ≠ 'a' → dp[ 2][ 3 ] = 0 比较s[ 1]和s[ 3]: 'b' = 'b' → dp[ 2][ 4] = dp[ 1][ 3 ] + 1 = 1 + 1 = 2 比较s[ 1]和s[ 4]: 'b' ≠ 'c' → dp[ 2][ 5 ] = 0 比较s[ 2]和s[ 3]: 'a' ≠ 'b' → dp[ 3][ 4 ] = 0 比较s[ 2]和s[ 4]: 'a' ≠ 'c' → dp[ 3][ 5 ] = 0 比较s[ 3]和s[ 4]: 'b' ≠ 'c' → dp[ 4][ 5 ] = 0 6. 寻找结果 在填充dp表的过程中,我们记录最大值和对应的位置: 最大值为2,出现在dp[ 2][ 4 ] = 2 这意味着以位置1和位置3结尾有长度为2的重复子串 子串是s[ 1-2+1:1+1] = s[ 0:2 ] = "ab" 7. 复杂度分析 时间复杂度:O(n²),其中n是字符串长度 空间复杂度:O(n²) 8. 优化 我们可以优化空间复杂度到O(n),因为每次只需要前一行的信息: 9. 验证 对于s = "ababc": 最长重复子串是"ab"或"ba" 算法正确找到了"ab" 这个解法通过动态规划高效地找到了最长的重复子串,既保证了正确性又具有良好的时间复杂度。