leetcode3.无重复字符的最长子串
题目:
给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度。
思路:
滑动窗口算法。
- 最大子串长度 = 右下标 - 左下标 +1 ;
- 使用map记录字符的下标,key 为字符,value 为下标。
如果 map 的 key 出现重复,说明有重复字符了。 - 找出左下标 left,如果重复就刷新左下标。
代码:
public class LeetCode3 {
/**
* 关键的点:
* 使用map记录字符的下标,key 为字符,value 为下标。如果 map 的 key 出现重复,说明有重复字符了。
* 找出left左下标,如果重复就刷新左下标。 map.get(s.charAt(i))+1。
* 求解长度,可以用右下标减左下标。 i-left+1。
*/
public int lengthOfSubstring(String s) {
if (s == null) {
return 0;
}
//Char的泛型是 Character,别写错了
HashMap<Character, Integer> map = new HashMap<>();
int max = 0;
//左边界
int left = 0;
for (int i = 0; i < s.length(); i++) {
//如果出现重复的字符,就刷新滑动窗口的左下标.
if (map.containsKey(s.charAt(i))) {
//比较关键的点:
// 1)当前字符包含在当前有效的子段中,如:abca,当我们遍历到第二个a,当前有效最长子段是 abc,我们又遍历到a,
// 那么此时更新 left 为 map.get(a)+1=1,当前有效子段更新为 bca;
// 简单概括,就是 如果有重复元素,把重复的左边的元素移出就行了。
// 2)当前字符不包含在当前最长有效子段中,如:abba,我们先添加a,b进map,此时left=0,我们再添加b,发现map中包含b,
// 而且b包含在最长有效子段中,就是1)的情况,我们更新 left=map.get(b)+1=2,此时子段更新为 b,而且map中仍然包含a,map.get(a)=0;
// 随后,我们遍历到a,发现a包含在map中,且map.get(a)=0,如果我们像1)一样处理,就会发现 left=map.get(a)+1=1,实际上,left此时
// 应该不变,left始终为2,子段变成 ba才对。
//
// 为了处理以上2类情况,我们每次更新left,left=Math.max(left , map.get(ch)+1).
left = Math.max(left, map.get(s.charAt(i))+1);
}
//使用map记录字符的下标
map.put(s.charAt(i), i);
//i - left + 1表示非重复子串的长度。i是右边界,left 是左边界。
max = Math.max(max, i - left + 1);
}
return max;
}
}
参考资料:
https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/