题目
题解
1.暴力遍历
这道题最常用的方法就是滑动窗口,由于我指针玩的不是很溜所以直接上的暴力遍历,一个字符一个字符的遍历其符合条件的子串。对于如何判断该字符是否重复,我用了一个数组,对每个字符的子串里的字符,如果字符满足a[s[i]]==0则该字符可以加入子串,然后记录它出现的次数,a[s[i]]++。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int lengthOfLongestSubstring(char * s){
if(strlen(s)==0)return 0;//注意字符串为空的特殊情况
int i=0;
int cnt=1;//初始值应该是1
int a[200]={0};
for(i=0;i<strlen(s);i++)
{
memset(a,0,sizeof(a));
a[s[i]]++;
int j=i+1,temp=1;
while(a[s[j]]==0&&j<strlen(s))//注意j的限制
{
a[s[j]]+=1;
j++;
temp++;
}
if(cnt<temp)
{
cnt=temp;
}
}
return cnt;
}
int main()
{
char s[200]={0};
scanf("%s",s);
int ans=lengthOfLongestSubstring(s);
printf("%d",ans);
}
注意:有个特殊情况容易忽略,字符串空的情况要返回0.
2.滑动窗口法
实际上就是搞两个指针,左指针指向当前字符,右指针指向当前字符开始的满足条件的子串的字符,窗口内的字符满足不重复。具体过程是,left指针不动,right指针增加直到出现不满足条件(不重复)的字符为止,然后left+1,重复直到left指向字符串末尾。可以看到,相比于前面的暴力遍历,每次都要从当前字符往后遍历,这种方法减少了遍历次数。时间复杂度变为了O(strlen(s))。
为什么right可以在上一个子串的基础上继续往右动呢?
以abcabcbb 为例:(图源官网题解)
可以看到随着当前字符的递增,子串结束的位置也是递增的。因为假设我们选择字符串中的第 k 个字符作为起始位置,并且得到了不包含重复字符的最长子串的结束位置为 r_k。那么当我们选择第 k+1个字符作为起始位置时,首先从 k+1到 r_k的字符显然是不重复的,并且由于少了原本的第 k个字符,我们可以尝试继续增大 r_k ,直到右侧出现了重复字符为止。