青训营—字符串最短循环字串

81 阅读2分钟

题目描述

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

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

测试样例

样例1

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

样例2

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

样例3

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

样例4

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

样例5

输入:inp = "abcdabcdabcdabcd"
输出:'abcd'

样例6

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

思路

  1. 长度限制:如果一个字符串 s 的长度为 n,那么它的重复子串的长度 len 必须是 n 的一个因子。也就是说,len 的取值范围是从 1n/2
  2. 构造与比较:对于每一个可能的子串长度 len,我们可以提取出字符串的前 len 个字符作为候选子串,然后构造一个新的字符串,通过重复这个子串 n / len 次来验证是否能够还原出原字符串。
  3. 效率考虑:由于我们只需要检查到 n/2 的长度,因此在最坏情况下,我们的算法复杂度为 O(n^2),但在实际情况中,由于字符串比较和构造的效率,通常会更快。

Java代码

public class Main {
    public static String solution(String inp) {
        // Edit your code here
        int n = inp.length();
        for (int len = 1; len <= n / 2; len++) {
            if (n % len == 0) {
                String substring = inp.substring(0, len);
                StringBuilder sb = new StringBuilder();
 
                for (int j = 0; j < n / len; j++) {
                    sb.append(substring);
                }
 
                if (sb.toString().equals(inp)) {
                    return substring; 
                }
            }
        }
        return "";
    }

    public static void main(String[] args) {
        // Add your test cases here
        
        System.out.println(solution("abcabcabcabc").equals("abc"));
    }
}

复杂度分析

时间复杂度:

  • 外层循环的最大迭代次数为 n/2,即 O(n)
  • 内层循环的拼接操作在最坏情况下需要执行 n/len 次,每次拼接的时间复杂度为 O(len),因此内层循环的时间复杂度为 O(n).
  • 因此,整体时间复杂度为 O(n^2),在最坏情况下(例如字符串为 aaaa...),需要检查所有可能的子串长度。

空间复杂度:整体空间复杂度为 O(n)