剑指 Offer II 119. 最长连续序列【中等题】
思路:【并查集】【哈希表】
单用哈希表也能过,但耗时 253 ms
基本思路就是将数组元素存入哈希set,然后遍历数组元素,设遍历到的当前元素为 num ,则如果set中存在num-1,则说明这个元素已经被num-1找过了,直接跳过;我们要找的连续序列的起始元素必须在此前从没被寻找过。
以num作为起点,num+1作为目标target,进入while循环,当目标target在列表中存在时,记录个数cnt++,目标右移,target++。
更新以当前元素作为起点的最长连续序列长度。
具体实现见代码1。
使用由哈希表存放父节点的并查集求解,耗时53 ms
基本思路及代码实现参考自评论区大佬 yukiyama
代码1:
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int max = 0;
for (int num : nums) {
if (set.contains(num - 1)) {
continue;
}
int cnt = 1, target = num + 1;
while (set.contains(target)) {
cnt++;
target++;
}
max = Math.max(max, cnt);
}
return max;
}
}
代码2:
class Solution {
public int longestConsecutive(int[] nums) {
if (nums.length <= 1){
return nums.length;
}
UnionFindByHashMap uf = new UnionFindByHashMap(nums);
//遍历 parents的key集合,尝试将key+1与key连通,即 key -> key+1
for (Integer key : uf.parents.keySet()) {
uf.union(key,key+1);
}
int max = 1;
for (Integer key : uf.parents.keySet()) {
//key指向的根节点就是key逐次加一能达到的最大值,那么以当前key为起点的最长连续序列的长度就是 find(key)-key+1
max = Math.max(max,uf.find(key)-key+1);
}
return max;
}
}
class UnionFindByHashMap {
int count;//记录连通分量
Map<Integer,Integer> parents;//记录节点key的根节点是value
/**
* 构造函数,对并查集进程初始化
* @param nums 要构建并查集的数组
*/
public UnionFindByHashMap(int[] nums){
this.parents = new HashMap<>();
//用哈希map对数组中的节点去重
//初始状态每个节点互不连通,每个节点的根节点就是自己
for (int num : nums) {
this.parents.put(num,num);
}
//初始化连通分量个数
this.count = this.parents.size();
}
/**
* 查找节点 x 的根节点
* @param x 传入节点
* @return 返回传入节点的根节点
*/
public int find(int x){
//当x节点的根节点就是x时,返回x
if (parents.get(x) == x){
return x;
}
//当x节点的根节点不是x时,递归查找此时x的根节点的根节点
parents.put(x,find(parents.get(x)));
//返回此时x的根节点
return parents.get(x);
}
/**
* 将 x 节点 和 y 节点进行连通
* @param x 传入节点
* @param y 传入节点
*/
public void union(int x,int y){
if (parents.containsKey(y)){
//直接将y放在x的value位置,表示令 x 指向 y
parents.put(x,y);
//连通之后连通分量减1
count--;
}
}
/**
* 返回当前的连通分量个数
* @return
*/
public int getCount(){
return this.count;
}
}