作者只是一个小白,最近希望能提升自己的代码水平,所以开始刷leetcode。写博客是为了整理自己的学习内容,难免会出错。如果有大大发现,非常欢迎指正哦!
题目:3、无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
实例:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
题解
这道题还是比较明显要用滑动窗口来做。我们想象有一个框在s字符串上滑动,框的两边都只能向右移动。
①框的right边每次向右移一步,使框内增加一个新字符;
②当新进入的字符与框内的字符不重复时,则right边向右移,left边不动。并将新的len = right-left+1和之前存储的旧len中的较大值存入len中;
③当新进入的字符与框内的字符重复时,则left边向右移,一直到框内字符不重复。重复第①步。
直到新字符为空,即整个字符串跑完,程序结束。
测试用例:s = “pwwelw”,left = right = 0,len = 0(为无重复字符最长长度), list = “”(为框内字符串)
- left = 0, right = 0, len = 1, list = “p”
- left = 0, right = 1, len = 2, list = “pw”
- left = 0, right = 2, len = 2, list = “pww”,检测到有重复字符,则left边向右移
- left = 1, right = 2, len = 2, list = “ww”
- left = 2, right = 2, len = 2, list = “w” ,没有重复字符,right边继续向右移
- left = 2, right = 3, len = 2, list = “we”
- left = 2, right = 4, len = 3, list = “wel”
- left = 2, right = 5, len = 3, list = “welw”
- left = 3, right = 5, len = 3, list = “elw”
10.left = 3, right = 6, len = 3, list = "elw空 ",因为新字符为空,结束。
代码一
执行用时:4ms
排名:超过 77% 提交记录
int lengthOfLongestSubstring(char * s){
int result = 0;
char *left = s , *right = s , *p;
while(*right != '\0'){
for(p = left; p < right ; p++){
if(*p == *right){
left = p + 1;
break;
}
}
result = (right - left + 1) > result ? (right - left + 1) : result;
right++;
}
return result;
}
这段代码就是按上面的思路写的。其中检查是否有重复字符,是通过for循环来判断。只要将新字符和框内每个字符进行比对就行。
那速度更快的代码是怎么样的呢?
代码二
执行用时:0ms
排名:超过 100% 提交记录
/*
使用 start 标识起始位置,end 结束字符,使用一个map标识是否遇到重复字符,遍历到有重复的字符,则start++。end - start + 1 就是不重复的字符串长度。
*/
int lengthOfLongestSubstring(char * s){
int start = 0, end = 0, maxlen = 0;
char map[128] = {0}; //收集字符,出现则ASCII对应位置为1
map[(int)*(s+start)] = 1;
while( *(s+end) != 0 )
{
maxlen = maxlen>(end-start+1)?maxlen:(end-start+1);
++end;
while( 0 != map[ (int)*(s+end) ] )//*(s+end)处的字符已经出现一次
{
map[ (int)*(s+start) ] = 0;
++start;
}
map[(int)*(s+end)] = 1;
}
return maxlen;
}
这段代码整体思路和上面的是一样的。区别就在于它判断重复字符的方式。它维护了一个map表,其中1代表对应的字符处于滑动窗口中,0代表不在窗口里。其中
map[(int)*(s+start)] = 1;
这一句我当时一下子没读懂。我们举个例子。
经过上一步map初始化后,map应该如下图所示,均为0。
map | 0 | 0 | 0 | 0 |
---|---|---|---|---|
index | …… | 112 | 113 | …… |
我们假设:
s = “pwew”,start = 0
那么*(s+start)就代表是s字符串的第一个字符“p”,而(int)*(s+start)就是取字符“p”的ASCII码,即112,所以将map[112]=1。如下表
map | 0 | 1 | 0 | 0 |
---|---|---|---|---|
index | …… | 112 | 113 | …… |
这一步理解了就比较简单了。1代表对应的字符处于滑动窗口中,0代表不在窗口里。我们之前是将新字符和前面窗口中所有其它字符进行比较,判断是否重复,而它就直接根据ASCII码查map表,看看是1还是0,就可以知道有没有重复了。
我感觉这其实也是一种哈希表,代替了for循环。以后要有意识多用用哈希表。