无重复字符的最长子串
3. 无重复字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 10^4
s
由英文字母、数字、符号和空格组成
滑动窗口,哈希表
哈希表记录窗口中每个字符的次数,如果添加了一个重复字符,则收缩左边界。
class Solution {
public int lengthOfLongestSubstring(String s) {
// 存储窗口(子串)中各个字符出现的次数
Map<Character,Integer> window = new HashMap<>();
// left 和 right 分别表示窗口的左右边界
int left = 0;
int right = 0;
int res = 0;
// while 循环通过右边界 right 遍历整个字符串。只有两个操作,移动边界和更新窗口。
while (right < s.length()) {
// 将右边界 right 所指向的字符 c 加入到窗口中
char c = s.charAt(right);
// 右边界无条件右移
right++;
// 更新哈希表中字符 c 的计数。
window.put(c, window.getOrDefault(c, 0) + 1);
// 如果刚刚添加了一个重复元素,此时要收缩窗口左边界,直到这个元素不再重复。
while (window.get(c) > 1) {
// 保存数据:记录下要移出的元素
char d = s.charAt(left);
// 收缩
left++;
// 更新哈希表中的数据
window.put(d, window.get(d) - 1);
}
// 窗口中无重复元素之后,记录下当前窗口的长度,注意窗口的长度是 right - left,可以这么想,第一次窗口中只有一个字符 s.charAt(right),但是 right++ 了,所以 right 在窗口的右边界右边一位。这行代码不能放在上面的while循环里,因为可能都不会进入那个while。
res = Math.max(res, right - left);
}
return res;
}
}
- 时间复杂度 O(N) : 其中 N 为字符串长度。
- 空间复杂度 O(1): 字符的 ASCII 码范围为 0 ~ 127,哈希表 dic 最多使用 O(128)=O(1) 大小的额外空间。