牛客-NC41-最长无重复子数组
NC41. 最长无重复子数组(medium)
方法一:HashSet+滑动窗口
思路:一道滑动窗口题(纯暴力是会超时的,注意看上图的备注信息。),其实很好理解:我们要找最长且无重复的子数组,无重复需要使用HashSet进行去重。要找到最长的,可以使用滑窗的思想去动态地改变长度。有以下情况(1)没有重复数组元素时,right指针一直往右移动,同时更新maxLen和window表。(2)当出现重复数组元素时,我们需要移除left指针所对应的元素,同时移动left指针,知道当前window表中不再出现重复元素(这里没有更新maxLen的原因是right指针没变,left在往右移动,所以此时形成的子数组长度肯定小于maxLen)。于是可以写出如下代码:
import java.util.*;
public class Solution {
/** * * @param arr int整型一维数组 the array * @return int整型 */
public int maxLength (int[] arr) {
// write code here
// 特判
int n = arr.length;
if (n <= 1) return n;
int maxLen = 1;
int left = 0, right = 0;
HashSet<Integer> window = new HashSet<>();
while (right < n) {
while (window.contains(arr[right])) {
window.remove(arr[left]);
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
window.add(arr[right]);
right++;
}
return maxLen;
}
}
时间复杂度: O(N), 最坏情况是left和right都遍历了一遍字符串。
空间复杂度: O(N), 我们需要window表来存放遍历到的值。
方法二:HashSet+滑动窗口(优化)
思路:对方法一做以下优化:当窗口存在重复元素,是一个一个元素的缩小窗口,可以使用HashMap记住每个元素在数组中的索引,当遇到重复元素时,可以直接跳到重复元素的后面。
import java.util.*;
public class Solution {
/** * * @param arr int整型一维数组 the array * @return int整型 */
public int maxLength (int[] arr) {
// write code here
// 当窗口存在重复元素,是一个一个元素的缩小窗口。
// 可以使用hashmap记住每个元素在数组中的索引,当遇到重复元素时,可以直接跳到重复元素的后面。
int n = arr.length;
if (n <= 1) return n;
int maxLen = 1;
int left = 0, right = 0;
HashMap<Integer, Integer> window = new HashMap();
while (right < n) {
Integer rightIndex = window.getOrDefault(arr[right], -1);
left = Math.max(left, rightIndex + 1);
maxLen = Math.max(maxLen, right - left + 1);
window.put(arr[right], right);
right++;
}
return maxLen;
}
}
时间复杂度: O(N), 最坏情况是left和right都遍历了一遍字符串。
空间复杂度: O(N), 我们需要window表来存放遍历到的值。
总结:本题自己想到使用滑窗和set来解决,写到后面对于当遇到重复元素怎么处理犯了愁。不知道left和right指针怎么移动才是正确的,没想到是只需要移动left指针,right指针是不能动的。通过移动left指针来让该窗口中没有重复的数组元素,达到去重的目的。另外,这里给出LeetCode上两道与之解法相近的题目,分别是无重复字符的最长子串以及剑指 Offer 48. 最长不含重复字符的子字符串。