返回

多维视角,深入理解LeetCode 2213题:揭秘重复字符串的妙解奥秘

后端

在LeetCode的挑战之旅中,2213题"由单个字符重复的最长子字符串"以其困难度吸引着无数算法爱好者。本文将从多个角度深入理解此题,为您揭示解决问题的奥秘。让我们共同开启这场探索算法之美的旅程!

问题陈述:
给定一个字符串s,你需要找出其中最长的由单个字符重复构成的子字符串的长度。

方法一:线段树

  • 构建一棵线段树,区间节点记录区间内相同字符的重复次数。
  • 从左到右遍历字符串,不断更新线段树上的区间节点值。
  • 在更新过程中,通过查询线段树获取当前区间内相同字符的最大重复次数,从而求得最长的重复子字符串长度。

方法二:动态规划

  • 定义dp[i]表示以字符串s的第i个字符为结尾的最长重复子字符串的长度。
  • 递推关系:dp[i] = dp[i-1] + 1 (s[i] == s[i-1])
  • 最终结果为max(dp[1], dp[2], ..., dp[n])

方法三:KMP算法

  • KMP算法是一种字符串匹配算法,也可以用于解决这个问题。
  • 构建失配表next[i],表示当模式串与文本串匹配到第i个字符时,模式串中下一个要匹配的字符的下标。
  • 利用next表,当模式串与文本串匹配到第i个字符时,若不匹配,则将模式串的匹配位置回溯到next[i]处继续匹配。
  • 在匹配过程中,当模式串与文本串完全匹配时,则更新最长重复子字符串长度。

代码实现:

方法一:线段树

import sys

class SegmentTree:
    def __init__(self, arr):
        self.n = len(arr)
        self.tree = [0] * (4 * self.n)
        self.build(arr, 1, 0, self.n - 1)

    def build(self, arr, node, start, end):
        if start == end:
            self.tree[node] = 1
            return
        mid = (start + end) // 2
        self.build(arr, 2 * node, start, mid)
        self.build(arr, 2 * node + 1, mid + 1, end)
        self.tree[node] = max(self.tree[2 * node], self.tree[2 * node + 1])

    def query(self, node, start, end, l, r):
        if l > end or r < start:
            return 0
        if l <= start and r >= end:
            return self.tree[node]
        mid = (start + end) // 2
        left = self.query(2 * node, start, mid, l, r)
        right = self.query(2 * node + 1, mid + 1, end, l, r)
        return max(left, right)

def longest_repeating_substring(s):
    tree = SegmentTree([0] * len(s))
    max_len = 0
    for i in range(len(s)):
        for j in range(i):
            if s[i] == s[j]:
                max_len = max(max_len, tree.query(1, 0, len(s) - 1, j + 1, i) + 1)
        tree.update(i, 1)
    return max_len

# 测试
s = "abbaba"
print(longest_repeating_substring(s))  # 3

方法二:动态规划

def longest_repeating_substring(s):
    dp = [0] * len(s)
    max_len = 0
    for i in range(1, len(s)):
        if s[i] == s[i - 1]:
            dp[i] = dp[i - 1] + 1
            max_len = max(max_len, dp[i])
    return max_len

# 测试
s = "abbaba"
print(longest_repeating_substring(s))  # 3

方法三:KMP算法

def longest_repeating_substring(s):
    n = len(s)
    next = [0] * n

    # 构建next表
    i, j = 1, 0
    while i < n:
        if s[i] == s[j]:
            j += 1
            next[i] = j
            i += 1
        else:
            if j > 0:
                j = next[j - 1]
            else:
                next[i] = 0
                i += 1

    # 利用next表匹配字符串
    i, j, max_len = 0, 0, 0
    while i < n:
        if s[i] == s[j]:
            j += 1
            max_len = max(max_len, j)
            i += 1
        else:
            if j > 0:
                j = next[j - 1]
            else:
                i += 1

    return max_len

# 测试
s = "abbaba"
print(longest_repeating_substring(s))  # 3

结论:
我们通过LeetCode的2213题深入探究了线段树、动态规划和KMP算法在重复字符串问题中的运用。这些算法各有优缺点,选择合适的方法取决于具体问题的情况。希望这篇文章对您理解这些算法及其应用有所帮助。