题目描述
给一个只含英文小写的字符串,求其最长的字符不重复的子串。比如字符串"abcabc",最长字符不重复子串长度为3,最长字符不重复子串为"abc","bca","cab";字符串"aaaaa",最长字符不重复子串长度为1,字符串为"a"。
输入
存在多个样例,每行输入一个字符串,串长不超过10000。
输出
每个样例先输出最长的字符不重复子串的长度,然后按字典序输出这些不重复子串,每个子串输出一行。
样例输入
abcabc aaaaa样例输出
3 abc bca cab 1 a
解题思路:
1. 依次找到从每个字符开始,理论上的最长子串长度。
2. 依次对找到的最长子串长度进行处理,如果在该区间中,出现重复字符,缩减子串长度。
3. 在缩减处理的同时,记录出现的最长子串长度,并记录下子串的初始位置。出现更优的要更新。
4. 将记录下来的子串, 转存进 结构体数组中,对结构体排序,按要求输出。
AC代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char str[30] = {0};
}Costring;
// 按字典序排序
int cmp(const void *p1,const void *p2){
return strcmp(((Costring *)p1)->str,((Costring *)p2)->str);
}
int main()
{
char str[10010] = {0};
while (scanf("%s",str+1) != EOF)
{
Costring Co_str[10010];
int i,j, Max_len = 0, cnt = 0;
// books 记录上一次该字母出现的位置; tags 记录 两个相邻的相同字符的位置关系,
int books[30] = {0}, tags[10010] = {0}, record[10010] = {0}; // record 记录最长子串的起始位置。
int len = strlen(str+1);
for (i = 1; i <= len; i ++)
{
tags[books[str[i]-'a']] = i; // 字符str[i] 上一次出现的位置 books[str[i]-'a'], 这一次出现位置 i,
books[str[i]-'a'] = i;
}// tags[k] = i, 表示理想状态下 有不重复子串从 k —> i-1
// eg: abcdabc (从下标1开始输入) tags[1] = 5, 即有 abcd 这一个不重复子串
// 但是像 abcbac tags[1] = 5, abcb 就不是一个不重复子串了, 后面还需要继续处理(34行)
for (i = 0; i <= 25; i ++) // 直到最后 字母没有再出现,tags[i] 记录为 字符串末尾。
if (books[i] != 0)
tags[books[i]] = len+1;
for (i = 1; i <= len; i ++)
{
int co_len = tags[i]; // 理论上最长长度
for (j = i; j < co_len; j ++) // 如果在这个区间内,有重复元素,则要更新子串长度。(这里手动模拟下会容易理解)
if (tags[j] < co_len)
co_len = tags[j];
tags[i] = co_len - i;
if (Max_len < tags[i]) {Max_len = tags[i]; cnt = 0;}
if (Max_len == tags[i]) record[cnt++] = i;
}
for (i = 0; i < cnt; i ++) // 把符合条件的最长子串转存进 结构体中
{
int strat = record[i];
for (j = 0; j < Max_len; j ++)
Co_str[i].str[j] = str[strat+j];
}
qsort(Co_str,cnt,sizeof(Costring),cmp); //排序, 输出处理
printf("%d\n",Max_len);
printf("%s\n",Co_str[0].str);
for (i = 1; i < cnt; i ++)
{
if (!strcmp(Co_str[i].str, Co_str[i-1].str)) continue;
printf("%s\n",Co_str[i].str);
}
}
return 0;
}