• 剑指offer_II_119 最长连续序列


    题目

    题目描述:

    给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
    
    输入:nums = [100,4,200,1,3,2]
    输出:4
    解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
    输入:nums = [0,3,7,2,5,8,4,6,0,1]
    输出:9
    
    0 <= nums.length <= 104
    -109 <= nums[i] <= 109
    

    实现

    主函数:为了测试UT

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

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

    1. /**
    2. * 暴力做法
    3. * 耗时32ms,内存消耗57MB
    4. *
    5. * @param nums 集合
    6. * @return 最长序列
    7. */
    8. private static int longestConsecutive(int[] nums) {
    9. if (nums.length <= 1) {
    10. return nums.length;
    11. }
    12. // DualPivotQuicksort双轴快排,数据量小插入排序,数据量大归并排序,时间复杂度O(n log(n))
    13. Arrays.sort(nums);
    14. // 去重时间复杂度O(n)
    15. int[] nums_distinct = Arrays.stream(nums).distinct().toArray();
    16. int longestLen = 0;
    17. int start = 0;
    18. int end;
    19. // 遍历一遍时间复杂度O(n)
    20. for (end = 1; end < nums_distinct.length; end++) {
    21. if (nums_distinct[end] != nums_distinct[end - 1] + 1) {
    22. start = end;
    23. }
    24. longestLen = Math.max((end - start + 1), longestLen);
    25. }
    26. longestLen = Math.max((end - start), longestLen);
    27. return longestLen;
    28. }

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

    1. /**
    2. * 哈希表遍历
    3. * 耗时17ms,内存消耗56.3MB
    4. *
    5. * @param nums 集合
    6. * @return 最长序列
    7. */
    8. private static int longestConsecutive(int[] nums) {
    9. if (nums.length <= 1) {
    10. return nums.length;
    11. }
    12. // 直接转成HashSet,add、delete、remove、contains时间复杂度O(1)
    13. Set set = Arrays.stream(nums).boxed().collect(Collectors.toSet());
    14. int longestLen = 0;
    15. for (Integer element : set) {
    16. // 即从[element, x]开始遍历到x
    17. if (!set.contains(element - 1)) {
    18. int currentElement = element;
    19. int currentLen = 1;
    20. while (set.contains(currentElement + 1)) {
    21. currentElement += 1;
    22. currentLen += 1;
    23. }
    24. longestLen = Math.max(longestLen, currentLen);
    25. }
    26. }
    27. return longestLen;
    28. }

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

    1. /**
    2. * 图论——并查集(Union-find Set)是一种精巧的数据结构,主要用于处理一些不相交集合的合并问题
    3. * 一些常见的用途有求连通子图、求最小生成树的Kruskal算法和求最近公共祖先(LCA)等
    4. * 主要操作:
    5. * 1、初始化 init
    6. * 2、查找 find
    7. * 3、合并 union
    8. */
    9. static class UnionFind {
    10. private Map parents;
    11. // 有参构造函数初始化哈希表,相当于用fa[]来存储每个元素的父节点。
    12. UnionFind(int[] nums) {
    13. this.parents = new HashMap<>();
    14. // 初始化时父节点设置为自己
    15. Arrays.stream(nums).boxed().forEach(element -> parents.put(element, element));
    16. }
    17. // 通过哈希表查询时间复杂度O(1)
    18. int find(int x) {
    19. // 递归出口,当到达了祖先位置,就返回祖先
    20. if (parents.get(x) == x) {
    21. return x;
    22. }
    23. // find(parents.get(x))不断往上查找祖先,也进行了路径压缩
    24. parents.put(x, find(parents.get(x)));
    25. return parents.get(x);
    26. }
    27. // 合并,把y作为x的parents
    28. void union(int x, int y) {
    29. if (parents.containsKey(y)) {
    30. parents.put(x, y);
    31. }
    32. }
    33. }
    34. /**
    35. * 哈希表 + 并查集 (「单向链表」转换成了「树」)
    36. * 耗时47ms,内存消耗61.3MB
    37. * @param nums 集合
    38. * @return 最长序列
    39. */
    40. private static int longestConsecutive(int[] nums) {
    41. if (nums.length <= 1) {
    42. return nums.length;
    43. }
    44. int longestLen = 0;
    45. UnionFind uf = new UnionFind(nums);
    46. for (int i = 0; i < nums.length; i++) {
    47. uf.union(nums[i], nums[i] + 1);
    48. }
    49. for (int i = 0; i < nums.length; i++) {
    50. longestLen = Math.max(longestLen, uf.find(nums[i]) - nums[i] + 1);
    51. }
    52. return longestLen;
    53. }

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

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

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

     3、合并如下图,i的祖先指向j的祖先

    最后将一些不相干的集合进行了合并。另外如果要进行路径压缩,则find函数查找祖先元素进行了路径压缩。

    备注:如果觉得写的有问题敬请指出,请大家以自己的判断力来了解并查集算法,毕竟我也是初步了解阶段,在此记录一下学习过程。

    并查集参考文献:

    1、并查集算法详解 - 知乎

    2、并查集从入门到出门 - 力扣(LeetCode)

    3、图论——并查集(详细版)_哔哩哔哩_bilibili

  • 相关阅读:
    [ 动词词组 ] 合集
    AcWing 196. 质数距离
    若依框架以及Mybatis-plus分页插件失效,数据库有多条却只查前十条
    Redis为什么是单线程的?Redis性能为什么很快?
    1513_人月神话阅读笔记_再论没有银弹
    关于CSDN右上角的消息数显示
    Zookeeper简述
    【AI+编程】工作日常场景随时可以AI编程,记一个问答SQL快速导出数据日常示例
    【C/C++笔试练习】初始化列表、构造函数、析构函数、两种排序方法、求最小公倍数
    Linux工具——gcc
  • 原文地址:https://blog.csdn.net/zkkzpp258/article/details/126453204