哈希表
先用哈希表去重,遍历哈希表中的元素num,如果num - 1不在哈希表中,说明num可以作为连续序列的左边界,然后不断查看num + 1,num + 2,… 是否在哈希表中,知道找到右边界,更新以num为左边界的连续序列的长度
若num - 1在哈希表中,说明无需再将当前num作为左边界,继续查找连续连续序列了
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> st;
for(int num : nums) st.insert(num);
int ans = 0;
for(int num : st){
if(st.find(num - 1) == st.end()){
// num - 1不存在于st中,num才能作为左边界
int r = num + 1;
while(st.find(r) != st.end()) r++;
ans = max(ans, r - num);
}
}
return ans;
}
};
并查集
构造一个连续序列的右边界作为根节点的并查集
遍历所有元素num,如果num+1存在于并查集中,连接num加入到num+1所在的连通分量,并将num+1所在集合的根节点作为父节点
重新遍历一遍所有元素num,通过find函数找到num所在分量的根结点,也就是最远右边界,从而求得连续区间的长度
class Solution {
public:
unordered_map<int, int> parent;
int find_root(int x){
// x不在并查集中
if(parent.find(x) == parent.end()) return INT_MIN;
if(x == parent[x]) return x;
parent[x] = find_root(parent[x]); // 路径压缩
return parent[x];
}
void merge(int x, int y){
x = find_root(x);
y = find_root(y);
if(x != y) parent[x] = y;
}
int longestConsecutive(vector<int>& nums) {
// 初始化并查集,自己的父节点就是自己
for(int num : nums) parent[num] = num;
for(int num : nums){
if(parent.find(num + 1) != parent.end()){
// num + 1存在于并查集中,连接num和num + 1所在的连通分量
merge(num, num + 1);
}
}
int ans = 0;
for(int num : nums){
ans = max(ans, find_root(num) - num + 1);
}
return ans;
}
};
封装并查集并添加记录连通分量的count
class UnionFind{
public:
UnionFind(const vector<int>& nums){
// 初始化并查集,自己的父节点就是自己
for(int num : nums) {
parent[num] = num;
count[num] = 1;
}
}
bool inline is_exist(int x){
return parent.find(x) != parent.end();
}
int find_root(int x){
// x不在并查集中
if(!is_exist(x)) return INT_MIN;
if(x == parent[x]) return x;
parent[x] = find_root(parent[x]); // 路径压缩
return parent[x];
}
// y比x大,y作为父节点,并查集建立完成后,根节点一定是一个连续序列的右边界
void merge(int x, int y) {
x = find_root(x);
y = find_root(y);
if (x != y) {
// x和y不属于同一连通分量,合并后再更新count
parent[x] = y;
int cnt = count[x] + count[y];
count[x] = cnt;
count[y] = cnt;
}
}
// 获取x所在连通分量的节点个数
int get_cnt(int x){
return count[x];
}
private:
unordered_map<int, int> parent; // 并查集
unordered_map<int, int> count; // 记录节点所在连通分量的节点个数
};
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.size() < 2) return nums.size();
UnionFind uf(nums);
int ans = 1;
for(int num : nums){
if(uf.is_exist(num + 1)){
// num + 1存在于并查集中,连接num和num + 1所在的连通分量
// 这样可以将连续的数字合入一个连通分量,改成num - 1也可以
uf.merge(num, num + 1);
ans = max(ans, uf.get_cnt(num));
}
}
return ans;
}
};