3.无重复字符的最长字串
题目链接
双指针
在题目中要求找出最长的无重复字串,重要的是不重不漏的找到所有的子串,然后找到字串中字符不重复的子串,最后在这些不重复字符的子串中找到长度最长的一个。可以以下标 \(i\) 为尾字符分为一类子串,那么只需要找到一个尽可能小的 \(j\) ,即长度最大, \([j, i]\) 这一段子串就是以\(i\)结尾的最长不重复子串(故后续枚举每一类即可)。
现在考虑一个问题,当我们的\(i\)进行移动的时候变为 \(i^,\) ,我们的 \(j^,\)一定是小于等于 \(j\) , 可以使用反证法证明。所以后续类别(以\(i^,\)为尾字符)的不重复子串的窗口左边界要么不移动,要么向右移动,所以可以使用一个哈希表来维护 \([j, i]\) 之间的字符出现的数量,每次 \(i\) 移动的时候,判定 \(j\) 应该移动到什么地方,会使得该窗口中不存在重复字符,取每一类中最长不重复子串的最大值即可。
因为两个指针最多遍历一遍数组,所以时间复杂度为:O(n)
CPP
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> heap;
int res = 0;
for(int i = 0, j = 0; i < s.size(); ++ i){
heap[s[i]] ++;
while(heap[s[i]] > 1) heap[s[j ++]] --;
res = max(res, i - j + 1);
}
return res;
}
};
Java
class Solution {
public int lengthOfLongestSubstring(String s) {
HashMap<Character, Integer> heap = new HashMap<>();
int res = 0;
char[] cs = s.toCharArray();
for(int i = 0, j = 0; i < cs.length; ++ i){
heap.put(cs[i], heap.getOrDefault(cs[i], 0) + 1);
while(heap.getOrDefault(cs[i], 0) > 1) heap.put(cs[j], heap.getOrDefault(cs[j ++], 0) - 1);
res = Math.max(res, i - j + 1);
}
return res;
}
}
如有错误,欢迎指正!