leetcode刷题3 无重复字符的最长子串

题目描述

给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。注意题中是最长子串,而不是子序列。

解题思路

这道题首先我想到的是依次遍历字符串中的字符,借助一个最长子串序列,每当遍历一个新的字符时,判断他是否在当前子串中出现,如果没出现过,将他记入最长字串中,如果出现了,则放弃当前子串,从下一个字符开始找起,直到找到每个该字符串中所有字符后边跟的最长子串,选取最大值即可,但是由于此算法时间复杂度太大,尤其是新加入字符时要依次比较最长子串中的所有字符,会报超出时间限制错误。
然后我看官方解题思路使用了滑动窗口,类似于一个双端队列,借助HashSet对象(不能存储相同数据),使用 HashSet 将字符存储在当前窗口 中。 当新元素满足要求,即未在子串中出现过时,将他加入子串,窗口向右移动加入此元素,当不符合要求时,窗口左侧移动,将重复元素移出窗口。
因为我是用C语言解题的,没有HashSet对象,我就类比滑动窗口的思想,然后结合其他大神的自己想了一种解法。首先,定义一个数组,该数组是字符的映射,类似于一种哈希表,例如出现了字符a,a的ASCII码是97,就对应于该数组中第97个元素,存储的数值是是该字符在给定字符床中出现的位置,这样非常方便查找某字符是否在当前子串中出现过,如果没有出现过将他加入当前子串即可,如果出现过根据滑动窗口的思想将重复字符及他之前的字符都移出当前子串。真正敲代码的时候还发现了一个特点,添加一个新的字符时,无论他是否重复出现,窗口右侧都要移动,而只有该字符是重复出现时,才移动窗口左侧。

我遇到的问题

1.首先就是超出时间限制,就是用了上边第一种算法,虽然思想简单,由于leetcode的设定,复杂度超过O(n2)的根本运行不出来。
2.还有一个初级错误我改了好长时间才发现,就是先定义的映射数组,为了方便判断是否重复出现,我先给他们赋了初始值,当初始值改变时就意味着此字符已经在当前子串中出现过了,赋初值的时候我是这样定义的:int map[128]={-1};,我以为这样数组内所有的值就会被赋值成-1,结果只有map[0]被赋成了-1;所以只好改成用for循环赋值
3.调试的过程中发现了一个问题,就是在移动窗口左侧时,一定要将移出去的这些字符们的重复标记,也就是辅助数组中对应的值恢复初始化-1,不然会出现逻辑错误,我开始是用的是原始字符串中的数组下标,但由于他本来就是由指针表示的,我就习惯性的把他在原始字符串数组中的下标当成了辅助数组中的下标,这样是不对的,辅助数组类似于哈希表,它是映射关系,并不是连续的,所以后边只好又加了一个指针标记,通过指针寻找由于重复需要在当前子串中删去的辅助数组位置标记。

源代码

int lengthOfLongestSubstring(char * s){
     
    int map[128];
    for(int j=0;j<128;j++)
    {
     
        map[j]=-1;
    }
    int left,right,size,max;
    left=right=size=max=0;
    char * p,* start;
    p=start=s;
    int i=0;
    while(*p!=NULL)
    {
     
        int temp=(int)(*p);
        if(map[temp]!=-1)
        {
        
            left=map[temp]+1;
            while(*start!=*p)
            {
     
                map[(int)*start]=-1;
                start++;
            }
            start++;
        }
        map[temp]=i;
        right=map[temp];
        size=right-left+1;
        if(max<size)
            max=size;
        i++;
        p++;
    }
    return max;
}

你可能感兴趣的:(leetcode刷题)