无重复字符的最长子串
难度:
标签:
题目描述
给定一个字符串 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
由英文字母、数字、符号和空格组成
代码结果
运行时间: 76 ms, 内存: 17 MB
// Problem: Find the length of the longest substring without repeating characters
// Approach: Java Streams are not the best fit for this problem due to its stateful nature, but we can simulate the sliding window approach using Streams in combination with additional state tracking.
// This solution is provided for completeness but is less efficient than using traditional loops.
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class StreamSolution {
public int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
BiFunction<Character, Integer, Integer> updateMap = (c, index) -> {
map.put(c, index);
return index;
};
int[] result = new int[1];
IntStream.range(0, s.length())
.boxed()
.collect(Collectors.toMap(i -> s.charAt(i), Function.identity(), (a, b) -> b, () -> map))
.forEach((c, i) -> {
if (map.get(c) != null && map.get(c) >= result[0]) {
result[0] = map.get(c) + 1;
}
map.put(c, i);
result[0] = Math.max(result[0], i - result[0] + 1);
});
return result[0];
}
}
解释
方法:
这个题解使用了滑动窗口的思路。用两个指针 l 和 r 表示滑动窗口的左右边界,用一个哈希表 memo 记录窗口内每个字符出现的次数。每次移动右指针 r,将新字符加入窗口,并更新哈希表。如果发现哈希表中新加入字符的次数大于1,说明有重复字符,则移动左指针 l 缩小窗口,并更新哈希表,直到窗口内没有重复字符为止。在移动过程中,用一个变量 ret 来记录最长无重复字符子串的长度。
时间复杂度:
O(n)
空间复杂度:
O(min(m, n))
代码细节讲解
🦆
为什么在更新最长无重复字符子串的长度时,使用`max(ret, r - l)`而不是其他方式?
▷🦆
哈希表`memo`的作用是什么?为什么要记录每个字符出现的次数?
▷🦆
当发现新加入的字符导致重复时,为什么只需要移动左指针`l`而不需要同时调整右指针`r`?
▷🦆
在内层while循环中,为什么要检查`if d in memo`再进行`memo[d] -= 1`操作?
▷相关问题
K 个不同整数的子数组
给定一个正整数数组 nums
和一个整数 k
,返回 nums
中 「好子数组」 的数目。
如果 nums
的某个子数组中不同整数的个数恰好为 k
,则称 nums
的这个连续、不一定不同的子数组为 「好子数组 」。
- 例如,
[1,2,3,1,2]
中有3
个不同的整数:1
,2
,以及3
。
子数组 是数组的 连续 部分。
示例 1:
输入:nums = [1,2,1,2,3], k = 2 输出:7 解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
示例 2:
输入:nums = [1,2,1,3,4], k = 3 输出:3 解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].
提示:
1 <= nums.length <= 2 * 104
1 <= nums[i], k <= nums.length