难度:中等
题目:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
提示:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
Related Topics
并查集
数组
哈希表
重点!!!解题思路
第一步:
明确解题手段
这种求连续的类似于连通性问题可使用并查集来解决
第二步:
题目中说以O(n)来解决此题,也就是说一次遍历来解决
原数组并未排序,所以我们要想一次遍历解决只能使用map集合帮助我们
例子中大部分差值为1,
所以,我们遍历数组发现map中有和当前值相差1的数,
就用并查集把它们两个连接起来。
第三步:
要求返回最长连续序列,即并查集中每个连通分量的大小
使用max方法逐一比较即可
源码:
class UnionFind {
//记录每个节点的根节点
int[] parent;
//记录每个子集的节点数
int[] rank;
//记录并查集中的联通分量数量
int count;
public UnionFind(int n){
count=n;
parent=new int[n];
for (int i=0;i<n;i++){
parent[i]=i;
}
rank=new int[n];
Arrays.fill(rank,1);
}
//路径压缩
public int find(int ind){
if (parent[ind]!=ind){
parent[ind]=find(parent[ind]);
}
return parent[ind];
}
//按秩合并
public void unite(int ind1,int ind2){
int root1=find(ind1),root2=find(ind2);
if (root1!=root2){
if (rank[root1]<rank[root2]){
int temp=root2;
root2=root1;
root1=temp;
}
parent[root2]=root1;
rank[root1]+=rank[root2];
count--;
}
}
public int getCount(){
return count;
}
public boolean connected(int ind1,int ind2){
return find(ind1)==find(ind2);
}
}
class Solution {
public int longestConsecutive(int[] nums) {
int ans=0;
HashMap<Integer,Integer> map = new HashMap<>();
UnionFind uf = new UnionFind(nums.length);
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(nums[i])) continue;
if (map.containsKey(nums[i]-1)){
uf.unite(i,map.get(nums[i]-1));
}
if (map.containsKey(nums[i]+1)){
uf.unite(i,map.get(nums[i]+1));
}
map.put(nums[i],i);
}
for (int i=0;i<nums.length;i++){//因为每个连通分量的根节点表示这个连通分量的总大小,所以没访问到根节点就跳过
if (uf.find(i)!=i) continue;
ans=Math.max(uf.rank[i],ans);
}
return ans;
}
}
运行结果:
如果您还有什么疑问或解答有问题,可在下方评论,我会及时回复。
系列持续更新中,点个订阅吧