LeetCode/最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
1. 暴力法
排序后遍历
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
//暴力
sort(nums.begin(),nums.end());
int n =nums.size();
if(n==0) return 0;
int count = 1;
int res = 1;
for(int i = 1; i < n; i++){
if(nums[i]==nums[i-1]) continue;
else if(nums[i]==nums[i-1]+1) count++;
else count = 1;
res = max(res,count);
}
return res;
}
};
2. 集合(哈希表)
先存储,再查找,跟两数之和那道题思路一样
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int n = nums.size();
if(n==0) return 0;
unordered_set<int> set_(nums.begin(),nums.end());
int res = 1;
for(int i=0;i<n;i++){
if(!set_.count(nums[i])) continue;
int count = 0;
int num = nums[i];
while(set_.count(num-1))
num--;//找到起始值
while(set_.count(num)){//遍历该序列
set_.erase(num);
num++;
count++;
}
res = max(res,count);
}
return res;
}
};
3. 并查集
遍历所有元素num,如果num+1存在,将num加入到num+1所在的连通分量中(从后往前效果更好)
最后每个集合的根节点为其右边界,为了union操作,必须知道指定数值的元素在哪个位置
因为每次合并不是邻近元素合并,所以不能光用一个数组记录根节点,还需要我们使用map容器记录值到索引的映射,从而帮助合并找到对应索引
索性直接用map记录值跟索引,因为我们只关心序列的长度,这里索引直接就是该集合的右边界,也就是根节点值
class Solution {
public:
unordered_map<int,int> series;//指针关系
unordered_map<int,int> count;//用于合并时计数
int max_ = 1;
int longestConsecutive(vector<int>& nums) {
if(nums.size()==0) return 0;
for(int num:nums){
series[num]=num;//每个数建立一个集合
count[num]=1;//初始值为1
}
for(int i = nums.size()-1; i>=0; i--)
if(series.count(nums[i]+1)) union_(nums[i]);
return max_;
}
void union_(int num){
int right1 = find(num);
int right2 = find(num+1);
if(right1==right2) return;
series[num]=right2;//合并集合
count[right2]=count[right1]+count[right2];//合并计数
max_ = max(max_,count[right2]);//记录最大值
}
int find(int num){
if(series[num]==num) return num;
series[num] = find(series[num]);//压缩路径
return series[num];
}
};