剑指 Offer II 119. 最长连续序列

剑指 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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值