Leetcode做题记录——最长连续序列

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

进阶:你可以设计并实现时间复杂度为 O(n) 的解决方案吗?

示例 1:

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

输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9

提示:

0 <= nums.length <= 104
-109 <= nums[i] <= 109


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这次开始的思路就是排序后扫描,时间复杂度O(n*log n),注意这里排序后要去重。

进阶的算法需要时间复杂度为O(n)这个我没想出来,看标签说是并查集,才想起来还有这么一个数据结构,扫描的时候把出现的相邻的数字不断合并,带上路径压缩,时间复杂度就是O(n)了。因为数字范围很大,所以需要先映射一下。

官方题解没有给出并查集的解法,用的是hash判断数字是否存在+扫描,扫描的时候枚举的数字n满足,n-1不存在,即找到每个连续段的第一个数字开始扫描,这样保证复杂度是O(n),非常巧妙。

hash判断数字+扫描代码:

class Solution {

    public int longestConsecutive(int[] nums) {
        int length = nums.length;
        if (length <= 1) {
            return length;
        }
        Set<Integer> set = new HashSet<>();
        for (int a : nums) {
            set.add(a);
        }
        int answer = 0;
        for (int a : nums) {
            if (!set.contains(a - 1)) {
                int count = 1;
                while(set.contains(a + count)) {
                    ++count;
                }
                if (count > answer) {
                    answer = count;
                }
            }
        }
        return answer;
    }
}

并查集代码:

class Solution {

    private int[] parent;
    private int[] size;

    public int longestConsecutive(int[] nums) {
        int length = nums.length;
        if (length <= 1) {
            return length;
        }

        Map<Integer, Integer> map = new HashMap<>();
        int index = 0;
        parent = new int[length + 1];
        size = new int[length + 1];
        for (int i = 0; i < length; ++i) {
            int v = map.getOrDefault(nums[i], 0);
            if (v == 0) {
                map.put(nums[i], ++index);
                v = index;
            } else {
                continue;
            }
            parent[v] = v;
            size[v] = 1;

            //查找前一个、后一个元素;
            int v1 = map.getOrDefault(nums[i] - 1, 0);
            int v2 = map.getOrDefault(nums[i] + 1, 0);
            int p1 = 0;
            if (v1 > 0) {
                p1 = find(v1);
                parent[v] = p1;
                ++size[p1];
            }
            if (v2 > 0) {
                int p2 = find(v2);
                if (p1 == 0) {
                    parent[v] = p2;
                    ++size[p2];
                } else {
                    parent[p2] = p1;
                    size[p1] += size[p2];
                }
            }
        }
        int answer = 0;
        for (int i = 1; i <= index; ++i) {
            if (size[i] > answer) {
                answer = size[i];
            }
        }
        return answer;
    }

    private int find(int v) {
        if (v == parent[v]) {
            return v;
        } else {
            parent[v] = find(parent[v]);
            return parent[v];
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值