版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012736685/article/details/88431345
一、题目描述
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
二、示例
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
三、分析
- 思路一:使用sort排序,然后查找最大的连续序列。因为题目要求时间复杂度为
O(N)
,这种方式不可用。 - 使用并查集
参考资料:
- https://www.cnblogs.com/xzxl/p/7226557.html
- https://blog.csdn.net/qq_41593380/article/details/81146850
四、实现
并查集一般包含创建函数,查找函数,合并函数。
本代码设计很精妙,使用了并查集模块,在模块里直接定义了并查集的数组,以及查找函数和合并函数。
class Solution {
// 并查集模板(已优化)
struct DisJointSet
{
vector<int> _id; // 元素
vector<int> _size; // 集合内的元素个数
int max_size; // 最大集合的元素个数【额外需要用到的参数】
int _count; // 集合总个数
DisJointSet(int Num)
{
for (int i = 0; i < Num; i++)
{
_id.emplace_back(i);
_size.emplace_back(1);
}
_count = Num;
max_size = 1;
}
// 查找
int find_(int p)
{
while (p != _id[p])
{
p = _id[p];
}
return p;
}
// 合并
void _union(int p, int q) {
int i = find_(p);
int j = find_(q);
if (i == j)
return;
if (_size[i] > _size[j])
{
_id[j] = i;
_size[i] += _size[j];
max_size = max(max_size, _size[i]);
}
else
{
_id[i] = j;
_size[j] += _size[i];
max_size = max(max_size, _size[j]);
}
_count--;
}
};
public:
int longestConsecutive(vector<int>& nums) {
if (nums.size() == 0)
return 0;
DisJointSet disJointSet(nums.size());
// 记录是否有查复数字 或者 是否已经有数字的前后的数
unordered_set<int> nums_set;
// <数字,ID> 与并查集ID一一对应,不需改动模板参数
unordered_map<int, int> nums_disJointSetID_map;
for (int i = 0; i < nums.size(); i++)
{
if (nums_set.find(nums[i]) != nums_set.end())
// 存在重复数字
continue;
nums_set.insert(nums[i]);
nums_disJointSetID_map[nums[i]] = i;
// 是否有前一个数
if(nums_set.find(nums[i] - 1) != nums_set.end())
{
disJointSet._union(nums_disJointSetID_map[nums[i]], nums_disJointSetID_map[nums[i] - 1]);
}
// 是否有后一个数
if(nums_set.find(nums[i] + 1) != nums_set.end())
{
disJointSet._union(nums_disJointSetID_map[nums[i]], nums_disJointSetID_map[nums[i] + 1]);
}
}
return disJointSet.max_size;
}
};