Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
Your algorithm should run in O(n) complexity.
Example:
Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
tag: union find, array
method 1 sort
直接排序求解
method 2 set
利用set的特性,不断地remove
使用一个set,对每一个数,检查是否有它的前继和后继,如果有则推进,感觉相当于滑动窗口的变种,使用remove方法可以减少遍历的数据量
使用sort,实际上速度更快
public int longestConsecutive(int[] nums) {
int res = 0;
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
set.add(nums[i]);
}
for (int num:nums) {
if (set.remove(num)){
int prev = num-1;
int next = num+1;
while (set.remove(prev)) prev--;
while (set.remove(next)) next++;
res = Math.max(res, next-prev-1);
}
}
return res;
}
method 3 union find
https://www.cnblogs.com/yelir/p/11549392.html 并查集的介绍
- 使用并查集时par数组的值都是父结点的索引,所以不需要特殊考虑,需要考虑的是如何将原数组中的值和par数组中的索引对应起来,本题使用map
- 本题提供了如何求每个树的节点个数,使用一个额外的size数组,每次union的时候加起来即可
- par数组、find方法和union方法是模板代码,要牢记
vector<int> par;
vector<int> size;
int find_(int x){
if (par[x] == x) return x;
par[x] = find_(par[x]);
return par[x];
}
void union_(int x, int y){
int root1 = find_(x);
int root2 = find_(y);
if (root1 != root2){
par[root1] = root2;
size[root2] += size[root1];
}
}
int longestConsecutive(vector<int>& nums) {
if (nums.size() == 0) return 0;
unordered_map<int, int> map;
par.resize(nums.size(), -1);
size.resize(nums.size(), 1);
for (int i = 0; i < nums.size(); i++){
int num = nums[i];
par[i] = i;
map[num] = i;
}
for (int i = 0; i < nums.size(); i++){
int num = nums[i];
int index = map[num];
if (map.count(num - 1)) union_(map[num - 1], index);
if (map.count(num + 1)) union_(index, map[num + 1]);
}
int longest = 1;
for (int i : size) longest = max(i, longest);
return longest;
}
summary:
- set等效代替滑动窗口
- 并查集重点(本题并查集模板代码要牢记)