题目
给定一个字符串,请你找出其中不含有重复字符
的 最长子串
的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
关键点
1、哈希表
2、滑动窗口(以双指针实现)
思路
1、关键字:
重复字符---->出现1次及以上
模式识别:
涉及次数要考虑用哈希表,一般字符为key,下标为值。
重复字符-----------------》用哈希表解决重复性问题;
2、涉及子串----------------》用滑动窗口
总的思路:
其实就是维护一个符合题目要求的窗口,比如例题中的 abcabcbb,进入这个窗口为 abc 满足题目要求,当再进入 a,窗口变成了 abca,这时候不满足要求。所以,我们要移动这个窗口!
如何移动?
我们只要把窗口的左边的元素移出就行了,直到满足题目要求!
一直维持这样的窗口,找出窗口出现最长的长度时候,求出解!
代码
class Solution {
public:
int lengthOfLongestSubstring(string s) {
map<char,int> hashmap;
int i=-1,res=0;//i :左指针
for(int j=0; j<s.size(); j++){//j :右指针
//若没出现过,则加入子串
//哈希表或数组等的下标区间都是左闭右开,即[ ),所以hashmap.end()是哈希表的尾后迭代器
//hashmap.find(k)返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器;即,下面语句若为真,则hashmap中不存在s[j]
if(hashmap.find(s[j])==hashmap.end()){
hashmap[s[j]]=j;
}
else{
//若出现过,收缩窗口
//出现的重复字符可能已经不在当前移动窗口中(子串中),所以需要比较上一次出现的重复字符位置和当前移动窗口的起始位置来确定新移动窗口的起始位置
i=max(hashmap[s[j]],i);// 更新左指针 i
hashmap[s[j]]=j;
}
res=max(res,j-i);
}
return res;
}
};
-时间复杂度:O(n)。遍历字符串
-空间复杂度:O(m)。m为字符空间。
字符的 ASCII 码范围为 0 ~ 127,哈希表最多存m=128个字符,即使用O(m)= O(128) = O(1)大小的额外空间。
ASCII码值范围
计算机内,用1个字节(8位二进制数),表示7位ASCII码字符,最高位取0。所以ASCII码有2**7种组合即128种组合。