XTU-OJ 1264-字符不重复子串

题目描述

给一个只含英文小写的字符串,求其最长的字符不重复的子串。比如字符串"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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值