青训营伴学笔记丨MarsCode刷题日记丨字符串最短循环子串

29 阅读3分钟

问题描述

小M在研究字符串时发现了一个有趣的现象:某些字符串是由一个较短的子串反复拼接而成的。如果能够找到这个最短的子串,便可以很好地还原字符串的结构。你的任务是给定一个字符串,判断它是否是由某个子串反复拼接而成的。如果是,输出该最短的子串;否则,输出空字符串""

例如:当输入字符串为 abababab 时,它可以由子串 ab 反复拼接而成,因此输出 ab;而如果输入 ab,则该字符串不能通过子串的重复拼接得到,因此输出空字符串。

测试样例

样例1:

输入:inp = "abcabcabcabc"
输出:'abc'

样例2:

输入:inp = "aaa"
输出:'a'

样例3:

输入:inp = "abababab"
输出:'ab'

样例4:

输入:inp = "ab"
输出:''

问题理解

如果一个字符串可以由某个子串重复拼接而成,那么这个子串就是要找的最短循环子串。如果找不到这样的子串,则返回空字符串。

算法步骤

  1. 长度判断:首先,检查字符串的长度。如果字符串长度为1,直接返回空字符串,因为单个字符无法通过重复拼接得到。
  2. 子串生成:从长度为1的子串开始,逐步增加子串的长度,直到子串的长度达到字符串长度的一半。
  3. 子串验证:对于每个可能的子串,检查它是否可以通过重复拼接得到原始字符串。
  4. 返回结果:如果找到这样的子串,返回该子串;否则,返回空字符串。

具体步骤

  1. 遍历子串长度:从1到字符串长度的一半。
  2. 生成子串:对于每个长度,生成对应的子串。
  3. 拼接验证:将子串重复拼接,直到拼接后的字符串长度不小于原始字符串。
  4. 比较:如果拼接后的字符串与原始字符串相同,则该子串就是最短循环子串。
std::string solution(const std::string &inp) {
    // 获取字符串的长度
    int n = inp.length();
    
    // 如果字符串长度为1,直接返回空字符串
    if (n == 1) {
        return "";
    }
    
    // 遍历可能的子串长度
    for (int len = 1; len <= n / 2; ++len) {
        // 检查当前子串长度是否能整除字符串长度
        if (n % len == 0) {
            // 获取当前子串
            std::string sub = inp.substr(0, len);
            
            // 构建通过重复子串得到的字符串
            std::string repeated;
            for (int i = 0; i < n / len; ++i) {
                repeated += sub;
            }
            
            // 检查构建的字符串是否与原始字符串相同
            if (repeated == inp) {
                return sub;  // 找到最短循环子串
            }
        }
    }
    
    // 如果没有找到符合条件的子串,返回空字符串
    return "";
}

关键步骤解释

  1. 获取字符串长度:使用 inp.length() 获取字符串的长度。
  2. 特殊情况处理:如果字符串长度为1,直接返回空字符串。
  3. 遍历可能的子串长度:从1到字符串长度的一半进行遍历。
  4. 检查子串长度是否能整除字符串长度:使用 n % len == 0 判断。
  5. 获取当前子串:使用 inp.substr(0, len) 获取当前子串。
  6. 构建通过重复子串得到的字符串:使用循环将子串重复拼接。
  7. 比较构建的字符串与原始字符串:如果相同,返回当前子串。
  8. 返回空字符串:如果没有找到符合条件的子串,返回空字符串。