题目详情
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
你可以设计并实现时间复杂度为 O(n) 的解决方案吗?
题目分析
该题难点在于O(n),所以不能用排序
这里很明显,暴力解法是O(n2),那么就需要空间换时间。
于是我便想到利用map。
其中是<Integer,Integer>,然后代表的是区间.
例如,区间[3,5],hashmap中如此存放:(3:5),(5,3),左边界对应右边界,右边界对应左边界。
然后每加入一个新的元素,判断其-1,+1是否在hashmap中,则有四种可能,具体的时间复杂度是O(n),满足要求,但是常数时间有点大,所以速度不是很快.
在代码中我贴了详细的注释,代码有点长,但很多是重复操作,可以大大简化。不难理解。
代码
class Solution {
//要求O(n)
//思路有了,就是之前那个,可能不太正规
//就是Map中维护连续的边界
//左:右;右:左
//每次加入一个新的元素,则判断其-1,+1在不在map中
//四种情况,如果都在,则将左区间的左边界的值设为右区间的右边界的值,然后同理
//如果只有一个在,则举例,左的右边界+1,当前值的左边界为原始左边界,删除之前的右边界
//如果没有,则直接创建新的
//这样就是O(n)的,而且空间复杂度其实不高
//你加入进去是2:2,然后有个3,你将2:2设置为2:3,3,设置成2。如果是1,那么就是1:2,就是左右的设置不同
public int longestConsecutive(int[] nums) {
//区间集合
//左里放右,右里放左
Map<Integer,Integer> intervals = new HashMap<>();
Set<Integer> set = new HashSet<>();
int max = 0;
//遍历序列
for(int num : nums){
if(set.contains(num))continue;
set.add(num);
if(intervals.containsKey(num-1)&&intervals.containsKey(num+1)){
//将区间合并,只留下边界信息,中间删除
int leftIntervalLeftBorder = intervals.get(num-1);
int rightIntervalRightBorder = intervals.get(num+1);
intervals.remove(num-1);
intervals.remove(num+1);
intervals.put(leftIntervalLeftBorder,rightIntervalRightBorder);
intervals.put(rightIntervalRightBorder,leftIntervalLeftBorder);
max = Math.max(rightIntervalRightBorder-leftIntervalLeftBorder+1,max);
}
else if(intervals.containsKey(num-1)){
int leftIntervalLeftBorder = intervals.get(num-1);
intervals.remove(num-1);
intervals.put(leftIntervalLeftBorder,num);
intervals.put(num,leftIntervalLeftBorder);
max = Math.max(num-leftIntervalLeftBorder+1,max);
}
else if(intervals.containsKey(num+1)){
int rightIntervalRightBorder = intervals.get(num+1);
intervals.remove(num+1);
intervals.put(rightIntervalRightBorder,num);
intervals.put(num,rightIntervalRightBorder);
max = Math.max(rightIntervalRightBorder-num+1,max);
}
else{
intervals.put(num,num);
max = Math.max(1,max);
}
}
return max;
}
}