128. 最长连续序列 #
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
提示:
0 <= nums.length <= 10^5-10^9 <= nums[i] <= 10^9
解答:
非O(N) #
class Solution {
public int longestConsecutive(int[] nums) {
int len=nums.length;
HashSet<Integer> set=new HashSet<>();
for(int i:nums){
set.add(i);
}
int maxLen=0;
int laseMin=Integer.MAX_VALUE;
int laseMax=Integer.MAX_VALUE;
for(int i=0;i<len;i++){
if(laseMax!=Integer.MAX_VALUE&&laseMin!=Integer.MAX_VALUE){
if(nums[i]<=laseMax&&nums[i]>=laseMin)
continue;
}
int cur=nums[i];
int min=cur;
int max=cur;
int count=1;
while(set.contains(++cur)){
count++;
max=cur;
}
cur=nums[i];
while(set.contains(--cur)){
count++;
min=cur;
}
maxLen=Math.max(maxLen,count);
laseMin=min;
laseMax=max;
}
return maxLen;
}
}
非O(N),而且没有保存全部的区间范围,实际上比较鸡肋
O(N) 使用set #
可以使用一个HashSet来存放已经遍历过的区间:
class Solution {
public int longestConsecutive(int[] nums) {
// 特判:空数组就直接返回 0
if (nums == null || nums.length == 0) {
return 0;
}
// 1. 放入 HashSet 去重 + 便于 O(1) 查询
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
// 2. set2 用来记录每个数字所属的 [min, max] 区间
// 这样下次遇到这个数字,就不必重复向左、向右搜索
Set<Integer> set2 = new HashSet<>();
int maxLen = 0;
// 3. 遍历原数组 这里其实使用set进行遍历也可以,效果差不多,因为下面接着就是做set2.contains(num)的处理,所以效果差别不多
for (int num : nums) {
// 若 set2 里已经包含此数字,说明它之前被处理过,跳过
if (set2.contains(num)) {
continue;
}
// 找到 num 所在连续区间的左右边界
int left = num;
int right = num;
// 向左扩张
while (set.contains(left - 1)) {
left--;
}
// 向右扩张
while (set.contains(right + 1)) {
right++;
}
int curLen = right - left + 1;
maxLen = Math.max(maxLen, curLen);
//将此区间内所有数字都记录到 set2
for (int x = left; x <= right; x++) {
set2.add(x);
}
}
return maxLen;
}
}
这样可以实现O(N)的时间复杂度
O(N) 使用set判断x-1,也就是当前元素是否是开头 #
class Solution {
public int longestConsecutive(int[] nums) {
// 特判:空数组就直接返回 0
if (nums == null || nums.length == 0) {
return 0;
}
// 1. 放入 HashSet 去重 + 便于 O(1) 查询
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int maxLen = 0;
// 3. 遍历去重之后的数组,否则会超时
for (int num : set) {
if (set.contains(num-1)) {
continue;
}
int right=num;
int left=num;
// 向右扩张
while (set.contains(right + 1)) {
right++;
}
int curLen = right - left + 1;
maxLen = Math.max(maxLen, curLen);
}
return maxLen;
}
}
复杂度分析
- 时间复杂度:O(n),其中 n 为数组的长度。具体分析已在上面正文中给出。
- 空间复杂度:O(n)。哈希表存储数组中所有的数需要 O(n) 的空间。