题目
无重复字符的最长子串
给定一个字符串 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 表示子串的开始位置,rk 表示子串的当前位置。
我们可以利用 hash 来判断不重复子串。如果 hash 表中存在该字符串,就进入下次循环;如果不存在,就放入集合中然后在再移动右指针。
- 最后通过 ans 来保存最大子串长度,然后对比的就是
rk - i + 1
就是右指针- 左指针 + 1
复杂度时间复杂度 O(N)
空间复杂度 O(|Σ|)
解题代码
题解代码如下(代码中有详细的注释说明):
class Solution { public int lengthOfLongestSubstring(String s) { // hash 集合,记录每个字符串是否出现过 Set<Character> occ = new HashSet<>(); int n = s.length(); // 右指针,初始值为 -1, 相当于我们字符串在左边界的左侧 int rk = -1, ans = 0; for (int i = 0; i < n; i++) { if (i != 0) { // 左指针右移,删除一个字符 occ.remove(s.charAt(i - 1)); } while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) { // 指针右移 occ.add(s.charAt(rk + 1)); rk++; } // 第 i 到 rk 一个字符串是一个,最长的无重复的子串 ans = Math.max(ans, rk - i + 1); } return ans; } }
提交后反馈结果(由于该题目没有进行优化,性能一般):