一.题目
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
二.解析
首先是我自己的做法,两层循环+一个hashset去解决了这个问题,但是时间复杂度和空间复杂度都挺高的
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
if(s.equals("")) return 0;
Set<Character> set = new HashSet<>();
int ans = 1;
for(int i = 0;i < n;i ++) {
set.add(s.charAt(i));
for(int j = i + 1;j < n;j ++) {
if(!set.contains(s.charAt(j))) {
set.add(s.charAt(j));
ans = Math.max(ans, j - i + 1);
} else {
set.clear();
break;
}
}
}
return ans;
}
}
然后是别人的做法利用了滑动窗口,我觉得很妙,但是一开始没有看懂,就利用了下chatgpt帮我分析下代码,看懂之后就更觉奇妙
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
int ans = 0;
for(int i = 0,j = 0;i < s.length(); i ++) {
if(map.containsKey(s.charAt(i))) {
map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
} else {
map.put(s.charAt(i), 1);
}
while(map.get(s.charAt(i)) > 1) {
map.put(s.charAt(j), map.get(s.charAt(j)) - 1);
j++;
}
ans = Math.max(i - j + 1, ans);
}
return ans;
}
}
这个的思路如下:
- 创建一个 Map 来跟踪字符的出现次数。
- 设定两个指针,i 和 j,分别代表滑动窗口的右边界和左边界。
- 移动右指针 i,向右扩展窗口,同时更新字符在 Map 中的出现次数。
- 如果发现重复字符(即出现次数超过 1),移动左指针 j 并逐渐减少字符的出现次数,直到窗口内的字符都是唯一的。
- 在每次移动时,记录当前窗口大小,并且不断更新最大窗口大小。
- 最终得到的最大窗口大小即为最长不重复子字符串的长度。