字符串最短循环子串

92 阅读4分钟

这道题要求找到一个字符串的最短重复子串,即判断一个字符串是否可以由一个较短的子串重复拼接而成。如果可以,则返回该最短子串;如果不可以,则返回空字符串 ""。比如,对于字符串 abababab,我们可以找到重复的子串 ab,而 abcabcabcabc 则可以由 abc 组成。以下将从问题分析、解题思路、代码实现和复杂度分析等几个方面详细说明这道题的解决方法。

1. 问题分析

给定一个字符串,找到其最短的重复子串,如果存在这样的子串,说明这个字符串可以通过某个子串重复拼接得到。比如 abababab 可以由 ab 反复拼接得到,abcabcabcabc 可以由 abc 反复拼接得到,而 abcd 则没有这样的子串。

题目的本质是找到一个长度较短的子串,通过重复该子串,可以还原出整个字符串。因此,我们可以尝试从较短的子串开始,不断扩大子串的长度,判断是否能拼接出原字符串。

2. 解题思路

为了有效地解决这个问题,可以按照以下步骤进行:

  1. 遍历可能的子串长度:我们从长度为1的子串开始,逐渐增大子串的长度,直到长度达到字符串的一半。之所以不超过一半,是因为如果一个字符串能通过某个子串重复得到,那么子串的长度不可能超过字符串长度的一半。

  2. 判断字符串长度是否整除子串长度:如果当前的子串长度不能整除字符串总长度,那么这个子串长度就不可能通过重复来构造出整个字符串。例如,对于字符串 abcabcabc,子串 ab 的长度不能整除 abcabcabc 的长度9,因此 ab 不可能构造出整个字符串。只有在子串长度能整除字符串长度的情况下,才可能是有效的候选子串。

  3. 生成重复的字符串并进行比较:假设当前的子串长度为 len,那么我们可以通过重复 n / len 次该子串来构造一个新字符串。如果这个新字符串和原始字符串相同,就说明这个子串就是我们要找的最短重复子串;如果不相同,继续增大子串长度,直到找到满足条件的子串或遍历完所有可能的长度。

  4. 返回结果:如果找到符合条件的子串,就返回它;如果没有符合条件的子串,则返回空字符串 ""

3. 代码实现

按照上述思路,我们可以编写以下代码:

#include <iostream>
#include <string>

std::string findShortestRepeatingSubstring(const std::string &inp) {
    int n = inp.size();
    for (int len = 1; len <= n / 2; ++len) {
        if (n % len == 0) {  // 判断字符串长度是否能被子串长度整除
            std::string substring = inp.substr(0, len);
            std::string repeated;
            int repeatCount = n / len;
            
            for (int i = 0; i < repeatCount; ++i) {
                repeated += substring;
            }
            
            if (repeated == inp) {  // 检查是否与原字符串匹配
                return substring;
            }
        }
    }
    return "";
}

int main() {
    std::string inp;
    std::cout << "请输入字符串: ";
    std::cin >> inp;
    std::string result = findShortestRepeatingSubstring(inp);
    if (result.empty()) {
        std::cout << "输出: \"\"" << std::endl;
    } else {
        std::cout << "输出: \"" << result << "\"" << std::endl;
    }
    return 0;
}

4. 代码讲解

  • 外部循环for (int len = 1; len <= n / 2; ++len) 遍历所有可能的子串长度。
  • 条件判断if (n % len == 0) 确保字符串长度可以被子串长度整除。
  • 构造重复字符串:利用内循环 for (int i = 0; i < repeatCount; ++i) 通过重复子串构造新字符串。
  • 匹配检查if (repeated == inp) 检查构造的新字符串是否与原字符串相同,如果相同,则返回该子串。

5. 时间复杂度分析

  • 时间复杂度:外部循环最多运行 n/2 次,每次构造新字符串的复杂度为 O(n),因此总体时间复杂度约为 O(n^2)
  • 空间复杂度:由于只使用了几个字符串变量,空间复杂度为 O(n)

6. 总结

本题的核心在于判断一个字符串是否可以由某个短子串重复构成,解决方法就是通过逐步增加子串长度进行尝试。这种方法利用了整除特性和字符串比较,将搜索空间限制在可能的最小范围内。