1 题目
https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/
给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
2 思路
最长无重复子串的长度,确定这个子串,长度自然就知道了,难点就是不知道这个字符串的开始和结束在什么位置
2.1 暴力循环
最开始就是暴力循环,两层循环,把所有可能的开始和结束都找到
public int lengthOfLongestSubString(String s) {
if (s.isEmpty()) return 0;
if (s.length() == 1) return 1;
//两次循环
Set<Character> hashSet = new HashSet<>();
int maxLength = 1;
for (int i = 0; i < s.length(); i++) {
int currentLength = 0; // 每次循环都要初始化为0
for (int j = i; j < s.length(); j++) {
if (!hashSet.contains(s.charAt(j))) {
currentLength += 1;
hashSet.add(s.charAt(j));
if (maxLength < currentLength) {
maxLength = currentLength;
}
} else {
hashSet.clear();
currentLength = 1;
hashSet.add(s.charAt(j));
}
}
hashSet.clear();
}
return maxLength;
}
【注意】hashSet的使用
清空场景:
- 在循环内遇到不连续的字符串需要进行清空
- 一次查找结束后,仍然需要清空
【注意】hashSet中添加字符的时机
- 字符串不连续时,hashSet中添加字符
- 字符串如果出现,清空字符串后需要添加字符,因为当前字符在下次会被检测,让后currentLength赋值为1
【时间复杂度】
O
(
N
2
)
O(N^2)
O(N2)
当然暴力的解法在LeetCode中是Timeout的,因此需要对算法优化
2.2 滑动窗口
既然不知道开始和结束的位置,使用滑动窗口不断试探开始和结束,然后取其中最大的,这样时间复杂度就降下来了,时间复杂度O(n)
public int lengthOfLongestSubString(String s) {
if (s.isEmpty()) return 0;
if (s.length() == 1) return 1;
Set<Character> hashSet = new HashSet<>();
int end = 0, maxLength = 1;
for (int start = 0; start < s.length(); start++) {
while (end < s.length() && !hashSet.contains(s.charAt(end))) {
hashSet.add(s.charAt(end));
end++;
if (maxLength < end - start) {
maxLength = end - start;
}
}
// maxLength = Math.max(maxLength, (end - start));
hashSet.remove(s.charAt(start));
}
return maxLength;
}
【注意】end从0开始,即将最开始的字符加进去
【注意】每次字符长度不能增加时,说明遇到相同的字符,此时从开始的地方逐步错小滑动窗口的大小
参考
<>