| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3452 人关注过本帖, 1 人收藏
标题:QA输出最长不重复子串(附加思维流程图)
只看楼主 加入收藏
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
结帖率:99.25%
收藏(1)
已结贴  问题点数:20 回复次数:37 
QA输出最长不重复子串(附加思维流程图)
图片附件: 游客没有浏览图片的权限,请 登录注册


弄了一个通宵,终于把代码抖出来了,感觉这个写得还是不错的。
在解决编程应用题的时候,一开始难免会遇到无从下手,找不到思路的情况,于是我就在写程序之前把程序框架以及思维流程模拟出来,个人觉得这种写流程图解编程应用题的方法不错,于是把一个样板拿出来给大家参考一下。

流程图就像起房子的图纸,写程序按照该流程图来写的。特别是遇到逻辑理解上档次的时候,写流程图能增强对程序的理解能力,而且找出错误的位置及其性质也会相对容易一些。

程序代码:
/*题目:找出最长没有重复字符的子串*/

/*
    #思路:

    1-建立ACSII表判断重复字符
    2-记录本串长度-两个重复字符出现的位置,以及第一个字符出现的位置
    3-下次判断以第一个字符的下一个字符开始,判断位置从子串端的下一个字符开始
    4-如果出现子串较长,则更记录最长新子串的位置
    5-执行上述操作用选择法出最长字符,以及最长子串的位置,读出数据

    #需要用到的主要变量:

    1-ASSII表ASS[256]
    2-起始指针p1(值为子串左端位置)
    3-检索指针p2(值为子串右端位置)
    4-记录指针p3(值为子串出现重复字符的左端位置)
    5-记录最长子串起始位置的指针p_Max
    6-记录子串长度变量L
    7-记录最长子串长度L_Max
    

    #需要用到的函数

    1-char *fun(char *p1,char **p2)
    说明:-记录最长子串。

    返回值:
          (条件分歧)如果检索指针p2没有走到尾部
    返回子串出现重复字符左端的位置p1
    (如果检索指针p2走到尾部)
          就返回起始位置,依然为p1
    返回后用l=p2-p3记录子串长度

    返回后把L_max与原L比较,如果L_max>L则记录最长子串指针p_Max=p1;

    #结构

    循环结构(循环执行条件: strlen(p1)>L_Max)/*就是说当p1指向剩余字符串长度大于所求子串最大值
    {
             (注意:)开头要用p3=p1;\\目的是保留本次字执行符串操作的起始位置
             尾部要加p1++,p2++;意思是移动指针从检索出重复字符的到下一个位置开始检验
    }*/

#include<stdio.h>
#include<string.h>

char *fun(char *p1,char **p2)
{
    static int ASS[256]={0};

    for (;++ASS[**p2]!=2&&**p2;++*p2);

    if (!**p2)
        return p1;

    for (--ASS[*p1];*p1!=**p2;--ASS[*p1])
          ++p1;

    return p1;
}

int main()
{
    char s[80];
    char *p1,*p2,*p3,*p_Max;

    int L,L_Max;

    L=L_Max=0;

    p_Max=p1=p2=p3=s;

    gets(s);

    while (strlen(p1)>L_Max)
    {
        p3=p1;    

        p1=fun(p1,&p2);

        L=p2-p3;

        if (L>L_Max)
        {
            L_Max=L;
            p_Max=p3;
        }

        p1++;
        p2++;
    }

    printf("%.*s\n",L_Max,p_Max);

    return 0;
}




[此贴子已经被作者于2016-12-9 03:54编辑过]

搜索更多相关主题的帖子: 能力 而且 应用题 流程图 
2016-12-09 03:52
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
收藏
得分:4 
我想我会用队列方式解决这个问题,每读入一个字符后,先与队列中保存的字符比较,如有相同的,则该字符之前的所有字符出队,新读入的添加在队列尾部,maxlen记录队列的最大长度

一切都在学习、尝试、摸索中
2016-12-09 05:58
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:4 
abcdab有3个不重复4码,只取最长值不取字串就简单点。
abcd
bcda
cdab


[此贴子已经被作者于2016-12-9 07:00编辑过]

2016-12-09 06:59
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
试试取出所有不重复最长的串
2016-12-09 07:05
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:528
帖 子:9025
专家分:54030
注 册:2011-1-18
收藏
得分:4 
以下是引用marlow在2016-12-9 05:58:32的发言:

我想我会用队列方式解决这个问题,每读入一个字符后,先与队列中保存的字符比较,如有相同的,则该字符之前的所有字符出队,新读入的添加在队列尾部,maxlen记录队列的最大长度

根据你描述的算法编写了代码,但未仔细检查
#include <stdio.h>
#include <string.h>

int foo( const char* s, int* plen )
{
    size_t idx = 0;
    *plen = 0;

    for( const char *p1=s,*p2=s; *p2; ++p2 )
    {
        const char* t = memchr( p1, *p2, p2-p1 );
        if( t )
            p1 = t+1;

        if( p2-p1+1 > *plen )
        {
            idx = p1-s;
            *plen = p2-p1+1;
        }
    }

    return idx;
}

int main( void )
{
    // 输入字符串(gets早被C废弃)
    //char s[80];
    //{
    //    if( fgets(s,sizeof(s)/sizeof(*s),stdin) == NULL )
    //        return 1; // 输入失败
    //    size_t n = strlen(s);
    //    if( n==0 || s[n-1]!='\n' ) // 缓冲区太小,需要将80加大
    //    {
    //        s[n-1] = '\0';
    //        return 2;
    //    }
    //}
    char s[80] = "abcdefgdfabcxyzaa";

    int len;
    int idx = foo( s, &len );
    printf( "%.*s\n", len, s+idx );

    return 0;
}

2016-12-09 09:15
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
收藏
得分:0 
/* maxsubstring.c 输出最长不重复子串*/
#include <stdio.h>
#include <string.h>
#define MAXSIZE 50

int main(void)
{
    int queue[MAXSIZE], sub[MAXSIZE];
    int front, rear, maxlen;
    int i, j, ch, flag = 1;
   
    queue[0] = getchar();         /* 读取第一个字符,不读取程序没办进行比较 */
    front = rear = maxlen = 0;      /* front,rear分别为队列第一,最后一个字符的下标 */
    while((ch = getchar()) != '\n' && maxlen < MAXSIZE){
        for(i = 0; i < rear + 1; i++)    /* 长度为rear+1的数组内查找相同的字符 */
            if(queue[i] == ch){           /* 如果找到了,则进行如下计算 */
                front = i + 1;
                for(j = 0; j < (rear - i); j++)  /* 从j开始,把rear-i个字符移动到队首 */
                    queue[j] = queue[front++];
                rear -= i;                        /* 重置队列尾部 */
                queue[rear] = ch;                 /* 把新读取的字符添加在尾部 */
                flag = 0;
                break;
            }
        if(flag)    /* 如果数组内没有找到相同的字符,则把新字符添加在队列尾部 */
            queue[++rear] = ch;
        else
            flag = 1;
        if(maxlen < rear + 1){   /* 保存数组最长记录*/
            maxlen = rear + 1;
            for(i = 0; i < maxlen; i++)   /* 记录下最长的子字符串 */
                sub[i] = queue[i];
            sub[i] = '\0';
        }
        front = 0;
//        for(i = 0; i <= rear; i++)            /* 此三行为调试用代码 */
//            printf("%c", queue[i]);
//        printf("\trear = %d\n",rear);
    }
    printf("最长的子字符串为:\"");
    for(i = 0; i <maxlen; i++)
        printf("%c", sub[i]);
    printf("\",共有%d个字符\n", maxlen);
   
    return 0;
}

一切都在学习、尝试、摸索中
2016-12-10 10:21
marlow
Rank: 6Rank: 6
等 级:侠之大者
威 望:2
帖 子:125
专家分:419
注 册:2016-7-18
收藏
得分:0 
这是昨天晚上在火车卧铺上整出来的代码,若要保存所有最长的字符串,觉得需要使用链表
欢迎指正

一切都在学习、尝试、摸索中
2016-12-10 10:22
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 4楼 吹水佬
我设想一个空间足够大的动态数组用来保存所有最长子串,但由于最长子串长度可能会发生变化,当最长子串长度发生变化时,缓冲区里面的子串也要跟着更新,而且容易造成空间浪费,不太好做,我尝试过了,不好实现;又设想先求最长子串长度,在此前提下再选出所有子串,但感觉在第一次基础上还要重复遍历一遍字符串,效率不高。或许是我未够火候,还请高手指教。

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2016-12-10 21:39
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
以下是引用九转星河在2016-12-10 21:39:56的发言:

我设想一个空间足够大的动态数组用来保存所有最长子串,但由于最长子串长度可能会发生变化,当最长子串长度发生变化时,缓冲区里面的子串也要跟着更新,而且容易造成空间浪费,不太好做,我尝试过了,不好实现;又设想先求最长子串长度,在此前提下再选出所有子串,但感觉在第一次基础上还要重复遍历一遍字符串,效率不高。或许是我未够火候,还请高手指教。

试试这样:
1、用一个动态数组作为存放当前最长字符串地址的列表。
2、每次比较得出较长的字符串时,先按数组地址列表释放当前保存的所有最长字符串,并释放动态数组。再重新创建动态数组保存当前最长字符串地址。
3、最后得到的数组地址列表就是所有最长字符串的地址。
4、释放所有动态分配的资源。
2016-12-11 06:21
吹水佬
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:451
帖 子:10607
专家分:43186
注 册:2014-5-20
收藏
得分:0 
回复 9楼 吹水佬
意思象这样,只是用动态处理。
#include <stdio.h>
main()
{
    char *s1="abcd";
    char *s2="ABCD";
    unsigned long a[2];
    a[0] = (unsigned long)s1;
    a[1] = (unsigned long)s2;
    char *p1 = (char *)a[0];
    char *p2 = (char *)a[1];
    puts(p1);
    puts(p2);
}


[此贴子已经被作者于2016-12-11 07:00编辑过]

2016-12-11 06:58
快速回复:QA输出最长不重复子串(附加思维流程图)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.056209 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved