无重复元素的最长子串(不是子序列,子序列可以不连续,子串必须是一段连续)
题意:
给出一个字符串,输出他的无重复元素的最长子串的长度:
- 无重复元素
- 最长
- 子串的字符在父串中连续,不可以间隔
方法一
- 如果s长度小于等于1,直接输出其长度
- 遍历每一个字符,维护两个指针,left无重复子串的左边界,right为当前遍历到的字符
- 当前字符在map中找到,left移到map中出现该字符的位置的下一个,更新map中该字符的出现位置
- 未找到,将该字符及位置加入map
- 当前子串长度为res和right-left+1中的较大值

//方法二
public int lengthOfLongestSubstring(String s) {
int l = s.length();
if (l <= 1) {
return l;
}
Map<Character, Integer> map = new HashMap<>();
int res = 0;
for(int left = 0, right = 0; right < l; right++){
char c = s.charAt(right);
if (map.containsKey(c)) {
left = Math.max(left, map.get(c) + 1);
}
map.put(c, right);
res = Math.max(res, right - left + 1);
}
return res;
}
方法二:重复时HashMap删除原位置i及之前的元素
hashMap也可以插入,也可以删除,但是HashMap是无序的,所以通过key删除,而不能通过i索引删除
- 当前字符串在map中出现过位置为i,清除i及其之前的所有字符,从此位置开始重新计算子串
//方法三
public int lengthOfLongestSubstring(String s) {
int l = s.length();
if (l <= 1) {
return l;
}
Map<Character, Integer> map = new HashMap<>();
int j = 0;
int res = 0;
for(int i = 0; i < l; i++){
if (!map.containsKey(s.charAt(i))) {
map.put(s.charAt(i), i);
res = Math.max(res, map.size());
}
else {
int end = map.get(s.charAt(i));
for(; j <= end; j++)
map.remove(s.charAt(j));
map.put(s.charAt(i), i);
}
}
return res;
}
方法三:==滑动窗口==。重复时Set删除原位置i及之前的元素,set为无序的,所以通过key删除,而不能通过i索引删除
是对方法二的改进,fast指针指向当前遍历位置,slow指针指向子串的开始位置
- 因为未用到map中的value:位置,所以hashMap可以改为hashSet,只存储字符即可
- 用while循环替代for,无需二层循环。找不到,存入并且找下一个;找到,移除slow位置的元素,因为fast不变,所以继续while循环,一直删除从slow删到fast位置的元素,此时fast元素不重复,执行if里的语句插入。
class Solution {
public int lengthOfLongestSubstring(String s) {
int res = 0;
Set<Character> set = new HashSet<>();
int slow = 0;
int fast = 0;
while(fast < s.length()){
if(!set.contains(s.charAt(fast))){
set.add(s.charAt(fast++));
res = Math.max(res, set.size());
}
else{
set.remove(s.charAt(slow++));
}
}
return res;
}
}
本文介绍了一种求解字符串中最长无重复字符子串的算法实现,包括三种方法:使用双指针与哈希映射,哈希映射结合滑动窗口,以及哈希集合与滑动窗口。这些方法在不同情况下有各自的优点。
348

被折叠的 条评论
为什么被折叠?



