字符串最短循环子串 | 豆包MarsCode AI刷题

208 阅读3分钟

在解答这个“字符串最短循环子串”问题时,我的目标是找到一个字符串的最短循环子串。如果字符串可以由一个较短的子串重复多次构成,那么这个较短的子串就是我们要找的最短循环子串。否则,就说明这个字符串不是由任何重复的子串构成,我们返回空字符串。

解题思路

  1. 寻找循环子串的基本思路

    • 我首先想到的是,如果一个字符串 inp 可以由一个子串 candidate 重复多次构成,那么字符串的长度 n 必须是 candidate 长度的整数倍。
    • 比如,字符串 "abcabcabcabc" 的长度是 12,它可以被 "abc" 重复 4 次构成,因此 abc 是该字符串的最短循环子串。
  2. 遍历所有可能的子串长度

    • 要找到最短的循环子串,我从最小长度 1 开始,逐步尝试更长的子串,直到 n // 2。因为如果子串长度大于 n // 2,即便重复两次也无法覆盖整个字符串,因此没有必要再尝试更长的子串。
    • 每次尝试的子串长度 l,如果 n 能被 l 整除,说明这个长度的子串有可能是循环子串,否则跳过。
  3. 验证子串是否可以重复构成整个字符串

    • 我取 inp 的前 l 个字符作为候选子串 candidate,然后将这个子串重复 n // l 次。
    • 如果重复后的结果等于原字符串 inp,则说明 inp 可以由这个子串 candidate 重复构成,因此这个子串就是我们要找的最短循环子串。
    • 一旦找到符合条件的子串,我就立即返回它,因为这是长度最短的候选子串。
  4. 特殊情况

    • 如果我尝试了所有可能的子串长度,仍然没有找到合适的循环子串,那么就说明 inp 不是由任何子串重复构成的,最终返回空字符串 ""

代码分析

在代码实现上,我使用了一个循环遍历所有可能的子串长度,然后通过条件判断和字符串重复比较,逐步找到最短的循环子串:

def solution(inp):
    n = len(inp)
    
    # 从长度 1 到 n//2 尝试所有可能的子串长度
    for l in range(1, n // 2 + 1):
        if n % l == 0:  # 只有当长度可以整除 n 时才可能是循环子串
            candidate = inp[:l]  # 截取候选子串
            if candidate * (n // l) == inp:  # 检查是否可以循环构成 inp
                return candidate
    
    return ""  # 没有找到循环子串,返回空字符串

复杂度分析

  • 时间复杂度:这个算法的时间复杂度是 (O(n)),因为我们只需要遍历字符串的前半部分(最多 n/2),并在每个长度上做一次重复拼接的检查。Python 的字符串操作效率较高,因此这样处理是高效的。
  • 空间复杂度:空间复杂度为 (O(1)),因为除了存储临时变量外,没有额外的存储需求。

总结

通过这个解法,我可以有效地找到一个字符串的最短循环子串。这种方法利用了字符串的长度特性和最小重复单位的概念,实现了高效的解决方案。这种思路适用于寻找周期性模式的字符串问题,比如检测字符串是否由重复模式构成。