给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
和最长递增子序列的区别是,本题不需要序列元素在原数组中连续,而最长递增子序列的递增要求在原数组中也要连续
这里考虑枚举的方法,对于数组的每个数x
,考虑其为起点,不断尝试x + 1, x + 2...
是否在数组中,如果最长匹配到了 x + y
,那么以x
为起点的最长连续序列即为x,x+1,x+2...x+y
,长度为y+1
,然后不断枚举即可
不过为了达到O(n)
的 时间复杂度,需要进行优化:
x+1,x+2,x+3...
是否在数组中,用哈希表查找,时间复杂度为O(1)
。x
。逐一遍历每个元素会产生很多重复工作,实际上无需一次针对每个元素x
去判断x+1,x+2,x+3...
是否在数组中。如果x-1
已经在数组中的话,那么x-1
肯定会进行相应的+1
遍历,然后遍历到x
,而且从x-1
开始的+1
遍历必定比从x
开始的+1
遍历得到的序列长度更长(因为必定多一个x-1
到x
这个长度)。因此,便可将在一个连续序列中的元素进行删减,让其只在最小的元素才开始+1遍历。比如,现有元素[1,2,4,3,5]
,当2,3,4,5
发现均有比自己小1
的元素存在,那么它们就不会开始+1
遍历(即x
发现有x-1
存在,那么就不会从自己开始遍历),而1
是连续序列中最小的元素,没有比自己小1
的元素存在,所以会开始+1遍历。通过上述方式便可将时间复杂度优化至O(n)
。java代码如下:
class Solution{
public int longestConsecutive(int[] nums){
//建立一个存储所有数的哈希表,同时起到去重功能
Set<Integer> set = new HashSet<>();
for(int x : nums){
set.add(x);
}
int ans = 0;
//遍历去重后的数字
for(int x : set){
int cur = x;//遍历到的当前数字,方便后续向后移动
//只有当x-1不存在时,才开始向后遍历x+1,x+2,x+3...
if(!set.contains(cur - 1)){
while(set.contains(cur + 1)){//只要后面的元素存在,则后移继续遍历
cur++;
}
}
//经过循环得到的[x, cur]之间是连续的,数字有cur - x + 1个
ans = Math.max(ans, cur - x + 1);
}
return ans;
}
}