• 【LeetCode-中等】128. 最长连续序列(详解)


    题目

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

    请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

    来源:力扣(LeetCode
    链接:https://leetcode.cn/problems/longest-consecutive-sequence

    题目分析

    灵感来源:

    作者:yimeixiaobai
    链接:https://leetcode.cn/problems/longest-consecutive-sequence/solution/xiao-bai-lang-ha-xi-ji-he-ha-xi-biao-don-j5a2/

    看到本题找最长连续序列,每个人都会想到两种最朴素的解法之一:

    1.先排序,从前往后找最长连续上升序列即可。该思路简单有效,但是复杂度已经至少有O(nlogn)O(nlogn)。实现起来也比较简单,在此不讨论该解法。

    2.遍历数组中的每个元素num,然后以num为起点,每次+1向后遍历num+1,num+2,num+3...,判断这些元素是否存在于数组中。假设找到的最大的连续存在的元素为num+x,那么这个连续序列的长度即为x+1。最后将每个num所开始序列长度取个最大值即可。
    这个思路很通俗易懂,实现成代码,如下所示:

    1. class Solution {
    2. public int longestConsecutive(int[] nums) {
    3. int n = nums.length;
    4. int ans = 0;
    5. // 遍历数组中的每个元素num
    6. for (int i = 0; i < n; i++) {
    7. // 以num为起点,每次+1向后遍历num+1,num+2,num+3...
    8. int cur = nums[i] + 1;
    9. while (true) {
    10. // 标识是否在数组中找到了cur
    11. boolean flag = false;
    12. // 在数组中找cur
    13. for (int j = 0; j < n; j++) {
    14. if (nums[j] == cur) {
    15. flag = true;
    16. break;
    17. }
    18. }
    19. if (!flag) {
    20. break;
    21. }
    22. cur += 1;
    23. }
    24. ans = Math.max(ans, cur - nums[i]);
    25. }
    26. return ans;
    27. }
    28. }

    方法1:哈希集合

    上面的代码是超时的,我们将它优化成不超时的。
    (1)用HashSet代替直接遍历,可以降低复杂度,而且可以去重复。
    (2)上面的方法的缺点:比如元素[1,2,4,3,5],上面的方法是:先选择1,遍历数组查找数组中有没有1+1=2,有的话再查找有没有2+1=3,以此查找到了5,然后再选择2,查找数组中有没有3,以此查找到5,这里就能看出出现了重复的代码,在选择1时,我们查找了2,3,4,5,,而选择2时,我们又查找了3,4,5,这样就重复了。

    我们的改进:遍历数组中每个元素num。逐一遍历每个元素会产生很多冗余工作,实际上我们无需一次针对每个元素num去判断num+1,num+2,num+3...是否在数组中。如果num-1已经在数组中的话,那么num-1肯定会进行相应的+1遍历,然后遍历到num,而且从num-1开始的+1遍历必定比从num开始的+1遍历得到的序列长度更长。因此,我们便可将在一个连续序列中的元素进行删减,让其只在最小的元素才开始+1遍历,也就是:只有当num-1不存在时,才开始向后遍历查找num+1,num+2,num+3

    比如,现有元素[1,2,4,3,5],当2,3,4,5发现均有比自己小1的元素存在,那么它们就不会开始+1遍历,而1是连续序列中最小的元素,没有比自己小1的元素存在,所以会开始+1遍历。通过上述方式便可将时间复杂度优化至O(n)。

    1. class Solution {
    2. public int longestConsecutive(int[] nums) {
    3. // 建立一个存储所有数的哈希表,同时起到去重功能
    4. Set set = new HashSet<>();
    5. for (int num : nums) {
    6. set.add(num);
    7. }
    8. int ans = 0;
    9. // 遍历去重后的所有数字
    10. for (int num : set) {
    11. int cur = num;
    12. // 只有当num-1不存在时,才开始向后遍历num+1,num+2,num+3......
    13. if (!set.contains(cur - 1)) {
    14. //查看数组中是否有 cur+1 ,有的话就继续查找 cur +1 +1
    15. while (set.contains(cur + 1)) {
    16. cur++;
    17. }
    18. }
    19. // [num, cur]之间是连续的,数字有cur - num + 1个
    20. ans = Math.max(ans, cur - num + 1);
    21. }
    22. return ans;
    23. }
    24. }

     这个方法就是对上面超时方法的一些改进,好理解

    感悟:当我们拿到一个题时,没有头绪时,不妨先写写你知道这个方法会超时的方法,然后思考如何将其改进,而不是一上来就想难的方法。

  • 相关阅读:
    1688API接口介绍详情
    微信8.0.27全面更新来了,这几个功能是否是你们喜欢的?
    淘宝API接口,item_search - 按关键字搜索淘宝商品(API 返回值说明)
    算法基础 动态规划 钢管问题
    以目标检测和分类任务为例理解One-Hot Code
    虚拟IP技术
    C51项目 - 可调万年历
    SpringSecurity(二十一)--OAuth2:实现资源服务器(中)实现带有JdbcTokenStore的黑板模式
    聚苯乙烯PS彩色胶乳微球:红色/蓝色/黑色/绿色胶乳微球介绍和制备方法
    软件测试/测试开发丨利用人工智能ChatGPT编写晋级报告
  • 原文地址:https://blog.csdn.net/KangYouWei6/article/details/127762500