【LeetCode】每日一题(八)128. 最长连续序列 并查集/哈希表

128. 最长连续序列

20200606

难度:困难

题目描述

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)

示例:

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

Solution

方法一

排序+比较

  • 先从小到大排序
  • 遍历数组,比较相邻的两项,如果相同,则跳过,继续遍历下一项
  • 如果 前一项+1 等于当前项,说明遇到连续项,cur +1
  • 否则,说明连续中断,将 cur重置为 1
class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums == null || nums.length == 0) return 0;
        Arrays.sort(nums);
        int max = 1;
        int cur = 1;
        for(int i = 1; i < nums.length; i++){
            if(nums[i] != nums[i-1]){
                if(nums[i-1] + 1 == nums[i]){
                    cur++;
                }else{
                    max = Math.max(max, cur);
                    cur = 1;
                }
            }
        }
        return Math.max(cur, max);
    }
}

方法二

HashSet

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 : set){
            if(!set.contains(num - 1)){
                int curNum = num;
                int curStreak = 1;
                while(set.contains(curNum + 1)){
                    curStreak++;
                    curNum++;
                }
                max = Math.max(max, curStreak);
            }
        }
        return max;
    }
}

方法三

参考题解

并查集UnionFind

UnionFindUml.png

  • max:记录节点集合的最大值
  • fatherMap:记录每个节点的父亲
  • sizeMap:记录每个节点所在集合的大小
class Solution {
    public int longestConsecutive(int[] nums) {
        if(nums == null || nums.length == 0) return 0;
        UnionFind uf = new UnionFind(nums);
        for(int i = 0; i < nums.length; i++){
            // 查看当前节点的上一节点是否在nums中
            if(uf.fatherMap.containsKey(nums[i]-1)){
                uf.union(nums[i]-1, nums[i]);
            }
        }
        return uf.max;
    }

    public class UnionFind{
        int max = 1;
        HashMap<Integer, Integer> fatherMap;
        HashMap<Integer, Integer> sizeMap;
        
        public UnionFind(int[] nums){
            fatherMap = new HashMap<>();
            sizeMap = new HashMap<>();
            // 初始化UnionFind,将所有节点指向自己,所有节点的size为1
            for(int val : nums){
                fatherMap.put(val, val);
                sizeMap.put(val, 1);
            }
        }
        //找到父节点并优化结构
        public int findFather(int val){
            int father = fatherMap.get(val);
            if(father != val){
                father = findFather(father);
            }
            fatherMap.put(val, father);
            return father;
        }

        public void union(int a, int b){
            int aFather = findFather(a);
            int bFather = findFather(b);
            if(aFather != bFather){
                int aFatherSize = sizeMap.get(aFather);
                int bFatherSize = sizeMap.get(bFather);
                //将bF作为aF的父亲
                fatherMap.put(aFather, bFather);
                sizeMap.put(bFather,aFatherSize + bFatherSize);
                max = Math.max(max, aFatherSize + bFatherSize);
            }
        }
    }
}

并查集相应的题目:

  • 128.最长连续序列 48.2% 困难
  • 130.被围绕的区域 39.7% 中等
  • 200.岛屿数量 47.6% 中等
  • 547.朋友圈 55.5% 中等
  • 721.账户合并 32.5% 中等
  • 839.相似字符串组 31.9% 困难
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值