C语言/数据结构字符串题解:最短循环节——找出能重复构成原串的最短基础子串

问题描述

小明在玩一个字符串拼接游戏时发现了一个有趣的现象:某些字符串可以通过重复一个较短的子串多次来构成。比如字符串 "abcabcabc" 可以由子串 "abc" 重复3次得到。这个较短的子串被称为字符串的"循环节"或"基础重复单元"。

现在小明想请你帮忙设计一个算法,给定一个非空字符串 s,找出能够通过重复构成整个字符串 s 的最短基础子串(即最短循环节)。如果存在多个这样的子串,返回任意一个即可。如果字符串无法由任何子串(除了整个字符串本身)重复构成,则返回整个字符串。

要求:

  1. 设计一个高效的算法来找到最短循环子串。
  2. 注意处理字符串可能无法由子串循环构成的情况(此时返回整个字符串)。

测试样例

样例1:

输入:s = "abcabcabc" 输出:"abc" 解释:整个字符串长度为9,可以由长度为3的子串"abc"重复3次(3×3=9)构成。

样例2:

输入:s = "aaaa" 输出:"a" 解释:整个字符串长度为4,可以由长度为1的子串"a"重复4次(1×4=4)构成。

样例3:

输入:s = "ababab" 输出:"ab" 解释:整个字符串长度为6,可以由长度为2的子串"ab"重复3次(2×3=6)构成。

样例4:

输入:s = "abcde" 输出:"abcde" 解释:整个字符串长度为5,无法由任何更短的子串重复构成(因为5是质数),因此返回整个字符串。

约束条件

  • 1 ≤ s.length ≤ 1000
  • s 仅由小写英文字母组成
  • 保证输入的字符串 s 非空

程序代码

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

char* shortestRepeatingSubstring(char* s) {

int n = strlen(s);

// 枚举循环节长度

for (int len = 1; len <= n; len++) {

// 长度必须能整除 n

if (n % len != 0) continue;

// 验证 s 是否由长度为 len 的前缀重复构成

int valid = 1;

for (int i = len; i < n; i++) {

if (si != si % len) {

valid = 0;

break;

}

}

if (valid) {

// 找到最短循环节,返回前 len 个字符

char* result = (char*)malloc((len + 1) * sizeof(char));

strncpy(result, s, len);

resultlen = '\0';

return result;

}

}

// 理论上不会到这里(因为 len=n 总是有效的)

char* result = (char*)malloc((n + 1) * sizeof(char));

strcpy(result, s);

return result;

}

int main() {

char* r1 = shortestRepeatingSubstring("abcabcabc");

char* r2 = shortestRepeatingSubstring("aaaa");

char* r3 = shortestRepeatingSubstring("ababab");

char* r4 = shortestRepeatingSubstring("abcde");

printf("%s\n", r1); // abc

printf("%s\n", r2); // a

printf("%s\n", r3); // ab

printf("%s\n", r4); // abcde

free(r1);

free(r2);

free(r3);

free(r4);

return 0;

}

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char* shortestRepeatingSubstring(char* s) {
    int n = strlen(s);
    
    // 枚举循环节长度
    for (int len = 1; len <= n; len++) {
        // 长度必须能整除 n
        if (n % len != 0) continue;
        
        // 验证 s 是否由长度为 len 的前缀重复构成
        int valid = 1;
        for (int i = len; i < n; i++) {
            if (s[i] != s[i % len]) {
                valid = 0;
                break;
            }
        }
        
        if (valid) {
            // 找到最短循环节,返回前 len 个字符
            char* result = (char*)malloc((len + 1) * sizeof(char));
            strncpy(result, s, len);
            result[len] = '\0';
            return result;
        }
    }
    
    // 理论上不会到这里(因为 len=n 总是有效的)
    char* result = (char*)malloc((n + 1) * sizeof(char));
    strcpy(result, s);
    return result;
}

int main() {
    char* r1 = shortestRepeatingSubstring("abcabcabc");
    char* r2 = shortestRepeatingSubstring("aaaa");
    char* r3 = shortestRepeatingSubstring("ababab");
    char* r4 = shortestRepeatingSubstring("abcde");
    
    printf("%s\n", r1);  // abc
    printf("%s\n", r2);  // a
    printf("%s\n", r3);  // ab
    printf("%s\n", r4);  // abcde
    
    free(r1);
    free(r2);
    free(r3);
    free(r4);
    
    return 0;
}

运行结果

相关推荐
学逆向的2 小时前
C 堆区内存管理
c语言·开发语言·网络安全
阿尼卡~5 小时前
VS Code 配置 C 语言开发环境(Windows 10/11):从 GCC 安装到运行、断点调试,一篇搞定
c语言·开发语言·windows
INGNIGHT8 小时前
91 · 最小调整代价(序列dp)
数据结构·算法·leetcode
从小白到软工13 小时前
5-2 从查表到控件:造按钮
c语言·开发语言·数据结构·经验分享·ai编程
水饺编程13 小时前
第2章:Linux 基础,解压缩【.tar.gz】压缩包
linux·c语言·汇编
cu14313 小时前
细谈IT6653的具体功能与其应用
c语言·c++·单片机·嵌入式硬件
夏虫不可与之言冰14 小时前
RMT 与 WS2812 灯带:可寻址 RGB 全彩控制
c语言·c++·单片机·物联网·visual studio
羊锦磊14 小时前
嵌入式基础1
c语言·c++·gnu
唐青枫14 小时前
C 语言 calloc() 详解:零初始化、动态数组与内存管理实战
c语言
David猪大卫15 小时前
【C++修炼】STL容器—stack与queue
c语言·开发语言·数据结构·c++·经验分享·笔记·学习