用java实现寻找最长无重复字符的子字符串(滑动窗口算法详解)
一、用java实现寻找最长无重复字符的子字符串
其中一种常见的方法是使用滑动窗口(sliding window)的技巧,即维护一个不含重复字符的子字符串,并用两个指针(start和end)表示其起始和结束位置。然后遍历整个字符串,每次将end指针向右移动一位,并检查当前字符是否已经在窗口中出现过。如果出现过,就将start指针向右移动到重复字符的下一个位置,并更新窗口。同时,记录下每次窗口的长度,并与最大长度进行比较,最后返回最大长度。
使用这种方法,可以在O(n)的时间复杂度和O(1)的空间复杂度内完成任务。
public int lengthOfLongestSubstring(String s) {
// 如果字符串为空或者长度为0,直接返回0
if (s == null || s.length() == 0) {
return 0;
}
// 定义两个指针start和end表示滑动窗口的起始和结束位置
int start = 0;
int end = 0;
// 定义一个数组来记录每个字符是否在窗口中出现过
boolean[] seen = new boolean[256];
// 定义一个变量来存储最大长度
int maxLength = 0;
// 遍历整个字符串
while (end < s.length()) {
// 获取当前字符对应的ASCII码值
int c = s.charAt(end);
// 如果当前字符已经在窗口中出现过,就将start指针向右移动到重复字符的下一个位置,并更新seen数组
while (seen[c]) {
seen[s.charAt(start)] = false;
start++;
}
// 将当前字符标记为已经出现过,并将end指针向右移动一位
seen[c] = true;
end++;
// 计算当前窗口的长度,并与最大长度进行比较,更新maxLength
maxLength = Math.max(maxLength, end - start);
}
// 返回最大长度
return maxLength;
}
二、滑动窗口算法详解
滑动窗口算法是一种常用的优化技巧,可以用来解决一些涉及数组或字符串的问题¹²³⁴⁵⁶。它的基本思想是维护一个连续的子数组或子字符串,称为窗口,并用两个指针(start和end)表示其起始和结束位置。然后根据题目要求,移动这两个指针来调整窗口的大小和位置,并在每次移动后更新所需的结果。
使用滑动窗口算法的好处是可以避免使用嵌套循环,从而降低时间复杂度。通常,滑动窗口算法可以将O(n2)或O(n3)的暴力解法优化为O(n)或O(n log n)的高效解法。
滑动窗口算法是一种在数组或字符串上执行操作的技术,它可以用一个固定大小的窗口来覆盖数组或字符串的一部分,然后不断地向前移动窗口,直到遍历完整个数组或字符串。¹²
滑动窗口算法可以将嵌套的循环问题转换为单循环问题,降低时间复杂度。⁴⁵
滑动窗口算法通常用双指针来实现,一个指针表示窗口的左端,另一个指针表示窗口的右端。根据题目的要求,可以调整窗口的大小和移动方式。³⁶
滑动窗口算法有很多应用场景,比如求解最长不重复子串、最小覆盖子串、最大连续子数组和等等。
滑动窗口算法也有一些变体,比如可以使用双端队列来实现窗口的更新,或者使用哈希表来存储窗口内的元素和频率。
下面我给你看一个滑动窗口算法的例题和代码吧。
题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
代码(Java):
class Solution {
public int lengthOfLongestSubstring(String s) {
// 使用哈希集合来存储窗口内的字符
//这行代码创建了一个名为set的新变量,它是一个Set类型的对象。
//Set是Java集合框架中的一种接口,它表示一组不包含重复元素的元素。
//HashSet是Set接口的一个实现,它使用哈希表作为其内部实现。
//这行代码创建了一个新的HashSet对象,并将其分配给set变量。这个HashSet对象将用于存储Character类型的元素。
Set<Character> set = new HashSet<>();
// 定义左右指针和最大长度
int left = 0, right = 0, maxLen = 0;
// 遍历字符串
while (right < s.length()) {
// 取出右指针指向的字符
char c = s.charAt(right);
// 如果该字符已经在集合中,说明出现了重复,需要缩小窗口
while (set.contains(c)) {
// 从集合中移除左指针指向的字符
set.remove(s.charAt(left));
// 左指针右移一位
left++;
}
// 如果该字符不在集合中,说明没有重复,可以扩大窗口
// 将该字符加入集合中
set.add(c);
// 右指针右移一位
right++;
// 更新最大长度为当前窗口大小
maxLen = Math.max(maxLen, right - left);
}
return maxLen;
}
}