思路
起点从零开始,向后枚举终点
- 如果终点位置的字符未出现过,则可加入不重复子串,终点后移
- 如果终点位置的字符已出现过,则不能加入到字串
- 计算当前找到的字串长度(终点-起点,注意坐标关系,终点位置字符不计入,所以左闭右开,直接相减即可),该长度与已记录的长度相比,取较大值
- 终点不动,起点不断后移,每次后移从当前子串中剔除“起点位置的字符”,直到当前子串不包含“终点位置的字符”
- 以当前的起点终点状态继续枚举终点
- 如果终点已超出字符串末尾(左闭右开),则计算枚举结束,计算字串长度取最大值
代码
class Solution {
public int longestSubstringWithoutDuplication(String s) {
HashSet<Character> set = new HashSet<>();
int len = s.length(), ans = 0;
int l = 0, r = 0;
while (r < len) { // 枚举终点
while (r < len && !set.contains(s.charAt(r))) { // 添加当前终点字符再后移终点 直到遇到重复字符或遍历完字符串
set.add(s.charAt(r));
r++;
}
ans = Math.max(ans, r - l); // 计算字串长度
if (r >= len) break; // 已遍历完 退出循环
while (set.contains(s.charAt(r))) { // 未遍历完 剔除起点字符再前移起点 直到终点字符可加入
set.remove(s.charAt(l));
l++;
}
}
return ans;
}
}
同一个思路 换个顺序 可以节省一些代码量
枚举终点,判断是否重复
- 重复则剔除起点字符并后移起点直到不重复
- 不重复,则可加入子串,更新已记录的子串最大长
最后添加终点字符到子串
class Solution {
public int longestSubstringWithoutDuplication(String s) {
HashSet<Character> set = new HashSet<>();
int len = s.length(), ans = 0;
for (int i = 0, j = 0; j < len; j++) {
if (set.contains(s.charAt(j)))
while (set.contains(s.charAt(j)))
set.remove(s.charAt(i++));
else
ans = Math.max(ans, j - i + 1);
set.add(s.charAt(j));
}
return ans;
}
}