给定一个字符串 s
,请你找出其中不含有重复字符的 最长 子串的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc"
,所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成
解题思路:
-
滑动窗口法:
- 使用两个指针
i
和r
分别表示当前窗口的左右边界。 - 初始时,两指针都指向字符串的起始位置,通过移动右指针
r
扩展窗口。
- 使用两个指针
-
Set 存储字符:
- 使用一个
HashSet
(set
)存储当前窗口内的所有字符,保证字符不重复。
- 使用一个
-
窗口扩展与收缩:
- 当右指针
r
指向的字符不在set
中时,将该字符加入set
,并向右移动r
。 - 如果发现重复字符(即
set
中已存在当前字符),则移动左指针i
,同时从set
中移除左指针所指向的字符,缩小窗口,直至窗口中不再有重复字符。
- 当右指针
-
更新最长子串长度:
- 每次移动右指针
r
时,更新最长不重复子串的长度length
,即为Math.max(length, r - i)
。
- 每次移动右指针
-
返回结果:
- 最终返回
length
,即最长不重复子串的长度。
- 最终返回
这种方法利用了滑动窗口和哈希集合的结合,实现了在线性时间内解决最长不重复子串的问题,时间复杂度为 O(n),其中 n 是字符串的长度。
class Solution {
/**
* 计算给定字符串 s 的最长不重复子串的长度。
* @param s 给定的字符串
* @return 返回最长不重复子串的长度
*/
public int lengthOfLongestSubstring(String s) {
int r = 0; // 右指针,用于扩展窗口
int n = s.length(); // 字符串 s 的长度
int length = 0; // 最长不重复子串的长度
Set<Character> set = new HashSet<>(); // 使用 set 存储当前窗口内的字符
for (int i = 0; i < n; i++) {
if (i != 0) {
set.remove(s.charAt(i - 1)); // 移除左指针对应的字符,缩小窗口
}
while (r < n && !set.contains(s.charAt(r))) {
set.add(s.charAt(r)); // 扩展右指针,加入字符到窗口
r++;
}
length = Math.max(length, r - i); // 更新最长不重复子串的长度
}
return length; // 返回最长不重复子串的长度
}
}