求字符串中最长无重复字符的子串

19 篇文章 0 订阅

题目:求一个字符串中最长的没有重复字符的子串。
例如字符串“abcdaefgh”
使用hash表记录是否之前的字符出现,具体代码如下:

//O(N^2)的时间复杂度
int max_unique_substring2(char * str) 
{
    int i,j;
    int begin;
    int maxlen = 0;
    int hash[256];
    int n = strlen(str);
    for(i=0; i<n; ++i)
    {
        memset(hash,0,sizeof(hash)); 
        hash[str[i]] = 1;
        for(j=i+1; j<n; ++j)
        {
            if(hash[str[j]] == 0)//如果之前没有出现,那么就讲对应的位置进行置1,若出现了,则break
                hash[str[j]] = 1;
            else
                break;
        }
        if(j-i > maxlen)//break之后,比较当前的最大不重复子串的长度与之前的长度哪个长
        {
            maxlen = j-i;//更新maxlen
            begin = i;
        }
    }
    printf("%.*s\n", maxlen, &str[begin]);
    return maxlen;
}

还有一种O(N)的算法,不是很好懂,先记录一下;
方法三:对字符串“axbdebpqawuva”构造下表:
这里写图片描述
表中,字符串有3个‘a’,有2个‘b’,其余为单一字符。next[]记录了下一个与之重复的字符的位置,如str[0]=str[8]=str[12]=‘a’,这时next[0]=8,next[8]=12,next[12]=13,其余同理。值得注意的是,对于没有重复字符的,next[]存储字符结束符‘\0’的下标,即13。
这里,first[i]表示i之后,第一次出现重复字符的那个位置。例如,str[0]之后,第一次出现的重复字符是str[5]=‘b’,当然,从str[1],str[2]开始也是一样。而从str[3]开始,要到str[12]才出现重复字符‘a’。可以证明,从str[i]起的最长符合要求的长度为first[i]-i,区间为[i,first[i]-1]由此得解。上述最长串是当i=3时,first[i]-i=12-3=9。结果最长无重复子串为“debpqawuv”。具体代码如下:

//O(N)的时间复杂度
int max_unique_substring3(char * str) 
{
    int maxlen = 0;
    int begin = 0;
    int n = strlen(str);
    int * next = (int*)malloc(sizeof(int)*n); //next[i]记录了下一个与str[i]重复的字符的位置
    int * first = (int*)malloc(sizeof(int)*(n+1)); //first[i]记录str[i]后面最近的一个重复点
    int hash[256];
    memset(hash,n,sizeof(hash));

    first[n] = n;
    for(int i=n-1; i>=0; i--)
    {
        next[i] = hash[str[i]];
        hash[str[i]] = i;
        if (next[i] < first[i+1])
            first[i] = next[i];
        else
            first[i] = first[i+1]; //生成first[]表,复杂度是O(N)的
    }
    for(int i=0; i<n; i++)
    {
        if (first[i]-i > maxlen)
        {
            maxlen = first[i]-i;
            begin = i;
        }
    }
    free(first);
    free(next);
    printf("%.*s\n", maxlen, &str[begin]);
    return maxlen;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值