题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,”pwke” 是一个子序列,不是子串。
题目分析
直接暴力枚举,双层循环,时间复杂度 O(n^2) ,显然不是好的做法。
使用双指针维护一个滑动窗口,用 HashSet 来确保窗口内字符不重复。
先用右指针尽可能的添加字符,无法添加时,就将左指针向右移动一位(同时在 set 中删除对应字符)。不断循环直到左指针移动到最右边,在这个过程中记录窗口的最大长度。
虽然代码上有2层循环,但从全局视角左指针和右指针都只会遍历一次字符串,因此时间复杂度是 O(n)。
Java
public int lengthOfLongestSubstring(String s) {
int ans = 0;
int left = 0, right = 0;
HashSet<Character> set = new HashSet<>();
while (left < s.length()) {
while (right < s.length() && !set.contains(s.charAt(right))) {
set.add(s.charAt(right++));
}
ans = Math.max(ans, right - left);
set.remove(s.charAt(left++));
}
return ans;
}
Kotlin
fun lengthOfLongestSubstring(s: String): Int {
var left = 0
var right = 0
var ans = 0
val length = s.length
val set = HashSet<Char>()
while (left < length) {
while (right < length && !set.contains(s[right])) {
set.add(s[right++])
}
ans = ans.coerceAtLeast(right - left)
set.remove(s[left++])
}
return ans
}