大厂面试手撕面试题:求一个字符串中最长不重复子串的长度(亲测可用的java实现)
这是一个常见的面试题,要求找到字符串中最长的不重复子串的长度。我们可以使用 滑动窗口 和 哈希集合 的方法来有效地解决这个问题。
思路:
- 滑动窗口:我们通过维护一个窗口来追踪当前不重复的子串。窗口的左边和右边分别由两个指针表示,我们通过右指针来扩展窗口,左指针则会根据需要收缩窗口。
- 哈希集合:为了高效检查一个字符是否已经在当前窗口中,我们可以使用哈希集合来存储窗口中的字符。
- 当我们遇到重复字符时,左指针会移动到重复字符之后的位置,确保窗口内的字符不重复。
具体步骤:
- 初始化一个空的哈希集合,用于存储当前窗口内的字符。
- 使用两个指针:
left
和right
。right
用于扩展窗口,left
用于收缩窗口。 - 如果当前字符(
s[right]
)不在哈希集合中,表示没有重复字符,将其加入集合,并更新最大长度。 - 如果当前字符已经在集合中,移动
left
指针,直到窗口中的字符没有重复。 - 每次移动
right
指针时,更新当前窗口的最大长度。
时间复杂度:
- 时间复杂度是 O(n),其中
n
是字符串的长度。因为每个字符最多只会被访问两次(一次通过右指针,另一次通过左指针)。
空间复杂度:
- 空间复杂度是 O(min(n, m)),其中
n
是字符串的长度,m
是字符集的大小(对于英语字符集而言,m
通常是常数 256)。
Java 代码实现:
import java.util.HashSet;
public class LongestUniqueSubstring {
public static int lengthOfLongestSubstring(String s) {
// 用一个哈希集合来记录当前窗口内的字符
HashSet<Character> set = new HashSet<>();
int left = 0; // 滑动窗口的左指针
int maxLength = 0; // 记录最长子串的长度
// 遍历字符串
for (int right = 0; right < s.length(); right++) {
// 当右指针指向的字符已经在集合中,收缩窗口
while (set.contains(s.charAt(right))) {
set.remove(s.charAt(left));
left++;
}
// 将当前字符加入集合
set.add(s.charAt(right));
// 更新最大长度
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
public static void main(String[] args) {
String s = "abcabcbb";
System.out.println("The length of the longest substring without repeating characters is: "
+ lengthOfLongestSubstring(s)); // Output: 3 ("abc")
}
}
代码解释:
set
是一个哈希集合,用来存储当前窗口中的字符。left
是滑动窗口的左指针,right
是滑动窗口的右指针。- 遍历字符串时,检查当前字符
s.charAt(right)
是否已经在窗口中。如果在,就不断移动left
指针,直到窗口内没有重复字符。 - 每次更新
right
指针时,计算当前窗口的长度,更新最大长度maxLength
。
示例:
对于输入 "abcabcbb"
:
- 经过滑动窗口的计算,最长的不重复子串为
"abc"
,长度为 3。