leetcode128. 最长连续序列hard

传送门

题目: 给定一个未排序的整数数组,找出最长连续序列的长度。 要求算法的时间复杂度为 O(n)。

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

方法1. Hash表

Hash表不一定要有映射, 只要证明出现过就行, hashset也可以.

  1. 所有数组元素入hash表(HashSet)
  2. 遍历数组元素num, 如果num-1不在hash表中,说明可以用num作为一个子序列的头, 循环开始找num++是不是在hash表中,累计连续子序列的长度count. 不用把找到的数从hash表中删除
	public int longestConsecutive(int[] nums) {
        Set<Integer> hash = new HashSet<Integer>();
        for (int num : nums) {
            hash.add(num);
        }
        int ans = 0;
        for (int i = 0; i < nums.length; i++) {
            int num = nums[i], count = 0;
            if (!hash.contains(num - 1)) {
                while (hash.contains(num)) {
                    count++;
                    num++;
                }
            } 
            ans = Math.max(ans, count);
        }
        return ans;
	}

方法2. 并查集

参考:这里

并查集主要的作用是 判断给定的一组数据是不是同一归属(祖先根节点是同一个)

就是在遍历数组的时候,比如遍历到num的时候,“查” nums是否在集合中,如果在就合"并"num和num-1

本题并查集DisjointSet的 数据结构:

Map<Integer, int[]> fatherMap   
Key: 当前节点的数值,
value: int[2] 长度2的数组, 
       [0]:存key的根节点数值, 
       [1]:存key根节点所在树包含节点个数
class Solution {
    public int longestConsecutive(int[] nums) {
        if (nums.length < 2) return nums.length;
        DisjointSet djSet = new DisjointSet(nums); //初始化并查集
        return djSet.getAns();
    }
}

class DisjointSet {    // 并查集 定义
    private Map<Integer, int[]> fatherMap;
    private int ans;//存所有  根节点所在树的   节点个数最大值
    DisjointSet(int[] nums) {
       //初始化1 因为如果数组都是重复数字,第二个for得if无效,就不会更新ans
        ans = 1; 
        fatherMap = new HashMap<Integer, int[]>();
        for (int num : nums) {
            fatherMap.put(num, new int[]{num, 1});
        }
        for (int num : nums) {
            
            if (fatherMap.containsKey(num - 1)) {
                // num-1和num都在的话, 合并两个树
                union(num, num - 1);
            }
        }
    }
    int findFather(int child) {// 查找child节点的根节点
        int[] root = fatherMap.get(child);
        if (root[0] == child)
            return child;
        
        int father = findFather(root[0]);  
        root[0] = father;//直接把chile连接到根节点,压缩树高  
        return father;
    }
    void union(int a, int b) {    // 合并 b树 到 a 树
        int aFather = findFather(a);
        int bFather = findFather(b);
        if (aFather == bFather) return;

        int[] aroot = fatherMap.get(aFather);
        int[] broot = fatherMap.get(bFather);

        broot[0] = aFather;       // 更新b树根节点为a树根节点
        aroot[1] = aroot[1] + broot[1];  // 更新a树 节点总数
        ans = Math.max(ans, aroot[1]);   // 找到最大的节点数
    }
    int getAns() {return ans;}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值