128. 最长连续序列
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
解题
将每个数去重保存在set中;
遍历set,若该存在比当前数小1的数,跳过当前数;
只找没有比当前数小1的数作为序列头!
找到序列头后,进行i++,cnt++,计算以该节点为头的序列长度;
视当前长度更新结果;
时间复杂度O(N);
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
for(auto n:nums) S.insert(n);
int res=0;
for(auto i:S){
if(i!=INT_MIN&&S.count(i-1)) continue;
int cnt=0;
while(S.count(i)){
i++;
cnt++;
}
if(cnt>res) res=cnt;
}
return res;
}
private:
unordered_set<int> S;
};
关键点
利用set对列表元素进行常数时间的查找!
方法2:并查集
设置uni字典,保存每个数字的父集;
设置size字典,作为并查集的优化,保存每个集合的大小;
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int n=nums.size();
if(!n) return 0;
res=1;
for(int t:nums){
uni[t]=t;
size[t]=1;
}
for(int t:nums){
if(uni.count(t-1)) unin(t,t-1);
//if(uni.count(t+1)) unin(t,t+1);
}
return res;
}
private:
int res;
unordered_map<int,int> size;
unordered_map<int,int> uni;
void unin(int a,int b){
while(uni[a]!=a) {
uni[a]=uni[uni[a]];
a=uni[a];
}
while(uni[b]!=b) {
uni[b]=uni[uni[b]];
b=uni[b];
}
if(a==b) return; //同一个集合,无需并
if(size[a]<size[b]){
uni[a]=b;
size[b]+=size[a];
size[a]=0;
}
else{
uni[b]=a;
size[a]+=size[b];
size[b]=0;
}
res=max({res,size[a],size[b]});
}
};
注意点:
每次遍历T,只需要查看比T大的,或比T小的是否存在,进行并集即可;
若大小都并的话,会造成重复合并;
虽然uni中设置了集合名称相同直接return,但也会耗时;