无重复字符的最长子串
题目
给定一个字符串
s
,请你找出其中不含有重复字符的 最长 子串 的长度。
示例
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
思路
- 最容易想到是暴力法,每遍历一个字符,就生成一个set,然后往后遍历,看以当前为底的字符最长多少不重复
- 进阶一点是滑动数组,思想就是保证滑块内的字符都不重复
- 这里使用一个map保存字符和他的数组位置,使用一个int类型的变量保存滑动数组的左边界,滑动数组的有边界是当前遍历的字符的下标
- 每遍历一个元素时,看map中是否包含该元素,如果不包含,那么滑动数组左边界不需要修改,直接把该字符和下标放入map中
- 如果包含,就分情况讨论了,一个是得到这个map中得到的元素的下标在left左边,说明滑动数组已经不包含该元素了,修改map中该字符的下标更新为最新的。
- 如果map中得到的元素下标在left右边,那么left需要修改为得到的这个下标加一,然后将该map中的元素的下标更新.
- left = Math.max(left, map.get(charArray[i]) + 1); 就是这段代码,实现了滑动数组的效果
- 计算子串长度。i - left + 1
代码实现
//滑动数组
public int lengthOfLongestSubstring(String s) {
int result = 0;
char[] charArray = s.toCharArray();
Map<Character, Integer> map = new HashMap<>();
int left = 0;
for (int i = 0; i < s.length(); i++) {
if (map.containsKey(charArray[i])) {
left = Math.max(left, map.get(charArray[i]) + 1);
}
map.put(charArray[i], i);
result = Math.max(result, i - left + 1);
}
return result;
}
//暴力法
public int lengthOfLongestSubstring01(String s) {
int result = 0;
char[] charArray = s.toCharArray();
for (int i = 0; i < charArray.length; i++){
HashSet<Character> set = new HashSet<>();
set.add(charArray[i]);
int temp = 1;
while ((temp + i < charArray.length) && !set.contains(charArray[i + temp])) {
set.add(charArray[i + temp]);
temp++;
}
result = Math.max(result, temp);
}
return result;
}