剑指offer_II_119 最长连续序列_uf = new newunionfind(len(nums))(2)

48 阅读2分钟

主函数:为了测试UT

    public static void main(String[] args) {
        int[] nums = new int[]{1, 2, 0, 1};
        int result = longestConsecutive(nums);
        System.out.println(result);
    }

暴力做法:时间复杂度O(n logn)

/**
     * 暴力做法
     * 耗时32ms,内存消耗57MB
     *
     * @param nums 集合
     * @return 最长序列
     */
    private static int longestConsecutive(int[] nums) {
        if (nums.length <= 1) {
            return nums.length;
        }
        // DualPivotQuicksort双轴快排,数据量小插入排序,数据量大归并排序,时间复杂度O(n log(n))
        Arrays.sort(nums);
        // 去重时间复杂度O(n)
        int[] nums_distinct = Arrays.stream(nums).distinct().toArray();
        int longestLen = 0;
        int start = 0;
        int end;
        // 遍历一遍时间复杂度O(n)
        for (end = 1; end < nums_distinct.length; end++) {
            if (nums_distinct[end] != nums_distinct[end - 1] + 1) {
                start = end;
            }
            longestLen = Math.max((end - start + 1), longestLen);
        }
        longestLen = Math.max((end - start), longestLen);
        return longestLen;
    }

哈希表遍历:时间复杂度O(n)

/**
     * 哈希表遍历
     * 耗时17ms,内存消耗56.3MB
     *
     * @param nums 集合
     * @return 最长序列
     */
    private static int longestConsecutive(int[] nums) {
        if (nums.length <= 1) {
            return nums.length;
        }
        // 直接转成HashSet,add、delete、remove、contains时间复杂度O(1)
        Set<Integer> set = Arrays.stream(nums).boxed().collect(Collectors.toSet());
        int longestLen = 0;
        for (Integer element : set) {
            // 即从[element, x]开始遍历到x
            if (!set.contains(element - 1)) {
                int currentElement = element;
                int currentLen = 1;
                while (set.contains(currentElement + 1)) {
                    currentElement += 1;
                    currentLen += 1;
                }
                longestLen = Math.max(longestLen, currentLen);
            }
        }
        return longestLen;
    }

哈希表+并查集:时间复杂度O(n logn)

/**
     * 图论——并查集(Union-find Set)是一种精巧的数据结构,主要用于处理一些不相交集合的合并问题
     * 一些常见的用途有求连通子图、求最小生成树的Kruskal算法和求最近公共祖先(LCA)等
     * 主要操作:
     * 1、初始化 init
     * 2、查找 find
     * 3、合并 union
     */
    static class UnionFind {
        private Map<Integer, Integer> parents;
        // 有参构造函数初始化哈希表,相当于用fa[]来存储每个元素的父节点。
        UnionFind(int[] nums) {
            this.parents = new HashMap<>();
            // 初始化时父节点设置为自己
            Arrays.stream(nums).boxed().forEach(element -> parents.put(element, element));
        }

        // 通过哈希表查询时间复杂度O(1)
        int find(int x) {
            // 递归出口,当到达了祖先位置,就返回祖先
            if (parents.get(x) == x) {
                return x;
            }
            // find(parents.get(x))不断往上查找祖先,也进行了路径压缩
            parents.put(x, find(parents.get(x)));
            return parents.get(x);
        }

        // 合并,把y作为x的parents
        void union(int x, int y) {
            if (parents.containsKey(y)) {
                parents.put(x, y);
            }
        }
    }

    /**
     * 哈希表 + 并查集 (「单向链表」转换成了「树」)
     * 耗时47ms,内存消耗61.3MB
     * @param nums 集合
     * @return 最长序列
     */
    private static int longestConsecutive(int[] nums) {
        if (nums.length <= 1) {
            return nums.length;
        }
        int longestLen = 0;
        UnionFind uf = new UnionFind(nums);
        for (int i = 0; i < nums.length; i++) {
            uf.union(nums[i], nums[i] + 1);
        }
        for (int i = 0; i < nums.length; i++) {
            longestLen = Math.max(longestLen, uf.find(nums[i]) - nums[i] + 1);
        }
        return longestLen;
    }

并查集的步骤主要有:初始化 ——>  查找 ——> 合并

1、初始化如下图,fa[]存储每个元素的父节点,初始化时每个父节点设置为自己。

2、查找如下图,找到i的祖先;

img img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取