题目
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。
思路-错误
使用双指针,在一个for循环里遍历,fast指针在前遍历字符串,low指针暂时待在起点,当char[fast] = char[low],说明出现重复字符,此时保存一下fast-low的长度,即当前获取到的一个不含重复字符的子串长度。
问题
fast向前移动过程中,low指针和fast指针中间可能会有重复字符。
比如abcbb
low指向a,fast往后移动时,char[low]==char[fast]始终不成立,但是有相同字符。
错误代码
//错误代码
void lengthOfChildString(Stirng s){{
if (s.length() < 2) {
return s.length();
}
char[] c = s.toCharArray();
int fast = 1;
int low = 0;
int result = 0;
while (fast < s.length()) {
if (c[fast] == c[low]) {
result = result > (fast - low) ? result : (fast - low);
low++;
} else {
fast++;
}
}
return result > (fast - low) ? result : (fast - low);
}
}
正确思路-使用map构建滑动窗口容器
map.containsKey()可以准确的判断出当前容器中是否含有遍历到的字符。
按照字符串顺序遍历到某个数的时候:
如果map中没有当前数,则直接放入map,容器大小+1
如果map中有当前数,则获取到已存在值的kv,把已存在的值包括之前的值全部移出map。或者将计算长度的左下标移动到刚刚匹配到的重复的字符下一个位置处。
代码
void lengthOfChildString(Stirng s){
//用作存储字符的容器
HashMap<Character,Integer> map = new HashMap<>();
// LinkList<Character> ll = new LinkedList<Character>();
//发现重复字符后移动的指针
int left = 0;
int result = 0;
for (int i = 0; i < s.length(); i++) {
//判断map滑动窗口中是否含有当前遍历的字符
if (map.containsKey(s.charAt(i))) {
//如果有,就把left指针往前移动。
left = left > (map.get(s.charAt(i))+1) ? left : (map.get(s.charAt(i))+1);
//i 2 3 4 5 6 7
//left 0 1 2 3 3 3
}
//else {
map.put(s.charAt(i), i);//a0,b1,c2,
//}
result = Math.max(result,i - left+1);//3 3 3 3 4 5
}
return result;
}
注意
滑动窗口移动过程中,每个元素都要插入。
注意上面注释掉的else{},如果判断map中有相同元素就不插入的话就会使下一次left的移动失败。left获取的还是前面重复字符的位置,导致出错,结果变大。
希望我永远都拥有开始的勇气。