最长连续序列LeetCode128

题目描述

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

要求算法的时间复杂度为 O(n)。题目来源

示例

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

题解及思路

思路1

题目要求时间复杂度为O(n)。大多数情况下,如果不需要限制时间复杂度的暴力法应该可以过,但是有这个要求,多多少少需要用到数据结构。按照题目的意思也就是找到公差为1的最长子数组。这里用到去重的集合Set,首先遍历一次,把所有的点加入到Set集合。然后重新遍历数组,在遍历数组的过程中,朝着一个方向按照公差为1的序列不断在set集合中查找,同时定义计数器保存最大值。这里给出代码,代码中是不断往后查找,往大的数方向查找。


public int longestConsecutive(int[] nums) {
        HashSet<Integer> num_set = new HashSet<>();

        for (int num : nums) {
            num_set.add(num);
        }

        int res = 0;
        for (int num : num_set) {
            if (!num_set.contains(num - 1)) {   // 保证只往一个方向找  放置重复找浪费时间
                int currentNum = num;
                int currentStreak = 1;

                while (num_set.contains(currentNum + 1)) {
                    currentNum++;
                    currentStreak++;
                }
                res = Math.max(res, currentStreak);
            }
        }

        return res;
    }

思路2

采用并查集的方法来做。同样也需要用到set集合,因为不知道传入数组的数据范围,所以采用map结构来定义parent数组,和计数数组。在联合的过程中同样也是判断集合中有没有公差为1的另一个数,有的话就进行联合,联合之后,更新父亲节点的深度。

    Map<Integer,Integer> parent;
    Map<Integer,Integer> count;  // 记录有多少个孩子节点,包括自身

    public int longestConsecutive(int[] nums) {
        parent = new HashMap<>();
        count = new HashMap<>();
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
            parent.put(num, num);
            count.put(num, 1);
        }

        int max = 0;
        for (int i = 0; i < nums.length; i++) {
            int t = nums[i];
            if (set.contains(t - 1)) { // 如果包含就进行联合。
                union(t - 1,t);
            }
            max = Math.max(max,count.get(find(t)));
        }
        return max;

    }


    private void union(int x, int y) {
        int x_root = find(x);
        int y_root = find(y);
        if (x_root == y_root) {
            return;
        } else {
            parent.put(x_root,y_root);
            // 更新深度
            count.put(y_root, count.get(x_root) + count.get(y_root));
        }
    }

    private int find(int x){
        int x_root = parent.get(x);
        if (x_root == x) return x_root;
        int x_root_root = find(x_root);
        // 提前进行树深度压缩
        parent.put(x,x_root_root);
        return x_root_root;
    }

但是这个方法会比第一个方法慢一些。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值