力扣3. 无重复字符的最长子串
题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解法1. 暴力循环
分析
既然是无重复字符,我们就可以让一个外循环控制最右侧的边界,内循环在这个范围内从左到右来依次检查是否出现重复字符。
重复字符的检测用Set即可。
时间复杂度O(n²),空间复杂度因为引入Set,所以是O(n)。
代码
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
if(len < 2) return len;
//将遇到的字符放进set,看是不是重复的。
Set<Character> set = new HashSet<>();
int start = 0;
char[] array = s.toCharArray();
int maxLen = 0;
while(start < len){
//从start开始,每次都往set里放元素,直到重复了。
for(int i = start; i<len; i++){
if(set.contains(array[i])){
//出现了重复元素,更新maxLen
maxLen = Math.max(maxLen, set.size());
//清空set
set.clear();
break;
}else{
//元素不重复,将字母放进去。
set.add(array[i]);
}
}
start++;
}
return maxLen;
}
}
解法2. 滑动窗口
分析
滑动窗口,先让左指针指向0,右指针依次往右走,如果遇到了重复元素,就将窗口左侧往右挪,挪到前面那个出现了重复的元素的右侧。然后更新最大值,并且更新重复元素的下标。
注意: 窗口只能往右去,不能往左回,所以窗口左侧更改位置时要比较一下当前位置和发生重复的元素的位置。
我们用Map来记录每个字符出现的位置。
代码
class Solution {
public int lengthOfLongestSubstring(String s) {
int len = s.length();
if(len < 2) return len;
//双指针,将遇到的字符放进Map,看是不是重复的。
Map<Character, Integer> map = new HashMap<>();
char[] array = s.toCharArray();
int maxLen = 0;
//窗口左指针
int start = 0;
for(int i = 0; i<len; i++){
//i是右指针
if(map.containsKey(array[i])){
//如果包含了此元素,说明重复,需要移动左指针
//窗口不能回退。
start = Math.max(map.get(array[i])+1, start);
}
//修改当前元素索引
map.put(array[i],i);
//计算长度
maxLen = Math.max(maxLen, i-start+1);
return maxLen;
}
}