嗡汤圆 2020-05-02
# 解题思路
对于无重复最长子串这类问题,通常可以采用两种解决方案:
(1)滑动窗口法,使用首尾两个指针来确定字符串范围
(2)用数组实现hashmap法
下面对两种解法分别进行探讨。
# 滑动窗口法
对于滑动窗口法需要设置两个指针,在对字符数组进行遍历的过程中每移动一个字符就要使用一次遍历判断一次该字符是否已经存在于先前存在的窗口中,如果存在,则将首指针指向前一重复元素的后一位,实现滑动的目的。得到的子串的长度每次都是尾指针对应下标减首指针对应下标,最后返回。从循环上来看,其时间复杂度为O(n^2),而变量的个数为常数,因此其空间复杂度为O(1)
滑动窗口法,我的题解代码如下,leetcode上运行时间4ms,内存占用5.6MB
int lengthOfLongestSubstring(char *s){//滑动窗口 int slen=strlen(s); int first=0,last=0,length=0,result=0; while(last<slen){ char tmpchar=s[last]; for(int i=first;i<last;i++){ if(tmpchar==s[i]){ first=i+1; length=last-first; break; } } last+=1; length+=1; result=length>result?length:result; } return result; }
# 用数组实现hashmap法
我们知道字符数组中的字符实质上是1-128的ASCII码,因此这里我们可以构建一个大小为128的整数数组,其中每个数组的位置都代表一个字符的位置,这样我们就可以通过这样数字和字符一一对应的数组来模拟hasmap操作,先将数组初始化为-1,之后设置两个首尾两个索引变量表示子串的边界,若在遍历过程中未出现重复的元素,则依次在对应的位置填入尾索引值,再对尾索引值加一,如果扫描到了一个重复的元素,该元素由于之前已经遍历过,其索引值必然大于等于首索引,因此可以判定出现重复元素,则代表首索引至第一个重复元素之间的子串作废了,将首索引跳至第一个重复元素的后一个索引值,来判断下一个子串,重复上面的操作。显然,这种方法只需要遍历一次字符数组,时间复杂度为O(n),而由于变量的个数和所占空间均为常数,其空间复杂度为O(1)。
数组模拟hashmap法,我的题解代码如下,leetcode上运行时间4ms,内存占用5.5MB
int lengthOfLongestSubstring(char *s){//利用数组实现hashmap int first=0,last=0,length=0,result=0; int slen=strlen(s); int vector[128]; for(int i=0;i<128;i++) vector[i]=-1; while(last<slen){ char tmpchar=s[last]; if(vector[tmpchar]>=first){//用数组中对应的值来表示索引 first=vector[tmpchar]+1; length=last-first; } vector[tmpchar]=last; last+=1; length+=1; result=length>result?length:result; } return result; }