描述
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
类似题目:最长不含重复字符的子字符串
思路1:滑动窗口
- 使用left、right双指针表示滑动窗口
- 每次窗口扩大时,遍历窗口中的元素
- 如果窗口中包含新元素,则缩小左边界
public class Solution {
public int maxLength (int[] arr) {
int ret = 0;
int left = 0;
int right = 0;
while(right < arr.length) {
for(int i = left; i < right; i++) {
if(arr[i] == arr[right]) {
left = i + 1;
break;
}
}
right++;
ret = Math.max(ret, right - left);
}
return ret;
}
}
思路2:滑动窗口+Map
同思路1,只不过使用Map记录滑动窗口中元素的最大位置,通过Hash查找,不需要遍历
- 使用left、right双指针表示滑动窗口
- 使用Map记录每个元素的最大索引
- 出现重复元素时,找到重复元素的索引,缩小滑动窗口
public class Solution {
public int maxLength (int[] arr) {
int ret = 0;
Map<Integer, Integer> map = new HashMap<>();
int left = 0;
int right = 0;
while(right < arr.length) {
if(map.containsKey(arr[right])) {
//重复元素可能在滑动窗口之外,此时左边界不需要移动
left = Math.max(left, map.get(arr[right]) + 1);
}
map.put(arr[right], right);
right++;
ret = Math.max(ret, right - left);
}
return ret;
}
}
思路3:滑动窗口+队列
类似思路1,使用队列存储滑动窗口中的元素,需要开辟额外的空间
- 使用left、right双指针表示滑动窗口
- 使用队列存储滑动窗口内的元素
- 出现重复元素时,缩小滑动窗口,将左边的元素全部移出
public class Solution {
public int maxLength (int[] arr) {
int ret = 0;
Queue<Integer> queue = new LinkedList<>();
for(int num : arr) {
while(queue.contains(num)) {
queue.poll();
}
queue.offer(num);
ret = Math.max(ret, queue.size());
}
return ret;
}
}