问题描述:
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里有并查集,我就往并查集的方向想了。
nums中数字n,若n-1出现在nums中,对n 和 n-1执行union操作。
Find方法中用到了路径压缩
最后对每个数字的父节点计算它的子节点的个数,这就是最长的连续数字
这里有一个坑就是数组中的数字可能会出现重复,若直接用数字来标识,那么会出现错误:
如:[0,0,-1]
若对数组中每一个数字进行find并对根节点+1的话,那么最后会得到3。
这里可以用下标来进行标识。
以上只是复习一下并查集。
因为我的并查集只打败了6% ಠ_ಠ
更快的方法:
使用集合存储数组中的数字。
对数组中的每一个数字,首先检查它是否还存在在集合中,若存在,将计数变量cnt设为0并从集合中删除该数字。
此时检查比它小1的数字是否存在,若存在删除它同时计数自增1一,再检查更小的。
对比它大1的数字同理。
当遇到这类问题时,我们不一定要考虑如何遍历数组,也可以考虑将其放到一个新的数据结构中。
代码:
Union Find:
class Solution { public: int longestConsecutive(vector<int>& nums) { unordered_map<int,int> parents; unordered_map<int,int> rec; for(int i = 0; i < nums.size(); i++){ parents[i] = i; rec[nums[i]] = i; } for(auto p : rec){ if(rec.count(p.first-1)){ Union(parents, rec[p.first-1] , rec[p.first]); } } return findMax(parents, nums); } private: int find(unordered_map<int,int> &parents, int a){ if(parents[a] == a) return a; return parents[a] = find(parents, parents[a]); } void Union(unordered_map<int,int> &parents, int a, int b){ int rootA = find(parents, a); int rootB = find(parents, b); if(rootA != rootB) parents[rootB] = rootA; } int findMax(unordered_map<int, int> &parents, vector<int> &nums){ int ret = 0; unordered_map<int,int> cnt; for(int i = 0; i < nums.size(); i++){ ret = max(ret, ++cnt[find(parents, i)]); } return ret; } };
使用集合:
class Solution { public: int longestConsecutive(vector<int>& nums) { unordered_set<int> s(nums.begin(), nums.end()); int ret = 0; for(int i = 0; i < nums.size(); i++){ if(s.count(nums[i])){ int cnt = 1; int prev = nums[i]-1; int next = nums[i]+1; s.erase(nums[i]); while(s.count(prev)){ s.erase(prev); prev--; cnt++; } while(s.count(next)){ s.erase(next); next++; cnt++; } ret = max(ret, cnt); } } return ret; } };