问题描述
给定一个字符串 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
由英文字母、数字、符号和空格组成
解题思路
利用set维护一个滑动窗口,逐个字符遍历字符串,并记录当前个数,遇到重复字符时更新最大个数。时间复杂度为O(n)。
AC代码
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int len = s.length();
int num = 0, maxNum = 0; // num记录当前值,maxNum记录当前最大值
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
// 若字符c出现过,则删除前一个字符c及其左侧的所有字符,相当于滑动窗口
if (set.contains(c)) {
if (num > maxNum) {
maxNum = num;
}
while (set.contains(c)) {
set.remove(s.charAt(i - num));
num--;
}
}
// 添加当前字符c
set.add(c);
num++;
}
// 最后也要更新一次
if (num > maxNum) {
maxNum = num;
}
return maxNum;
}
}
优化代码
利用双指针作为滑动窗口的左右边界,对于上面的代码稍微简化一下,增加可读性。
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int maxNum = 0, left = 0; // maxNum最大值,left为滑动窗口的左边界,right为滑动窗口的右边界
// 若字符c出现过,则删除前一个字符c及其左侧的所有字符,相当于滑动窗口
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
while (set.contains(c)) {
set.remove(s.charAt(left));
left++;
}
// 添加当前字符c
set.add(c);
maxNum = Math.max(maxNum, right - left + 1);
}
return maxNum;
}
}
(by 归忆)