3.最长连续序列

58 阅读2分钟

题目链接

给定一个未排序的整数数组 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

题解1 排序后计数

思路

在不考虑时间复杂度的情况下,最简单的方法就是将数组排序后,遍历计数。

代码

function longestConsecutive(nums: number[]): number {
    if (!nums.length) {
        return 0;
    }

    nums.sort((a, b) => a - b);
    let result: number = 1;
    let sequence: number = 1;

    for (let i = 0; i < nums.length - 1; i++) {
        if (nums[i + 1] === nums[i]) { // 去重
            continue;
        }
        if (nums[i + 1] - nums[i] === 1) {
            sequence++;
        } else {
            sequence = 1;
        }
        result = Math.max(result, sequence);
    }

    return result;
};

时空复杂度分析

时间复杂度:代码中有排序和遍历的开销,最大的是排序 O(n logn)

空间复杂度:只使用了2个变量,为 O(1)

题解2

思路

我们可以利用哈希表来缓存数组,这样查询序列中的其他数时很快。如果有比当前数小1的存在,则跳过;否则遍历它的序列。

为什么存在 n - 1 就跳过?因为要确保序列最长,所以要从最小的那个数开始遍历。如果存在 n - 1 那么,它一定不是最小的,也代表从 n 开始的序列一定不是最长的。

代码

function longestConsecutive(nums: number[]): number {
    if (!nums.length) {
        return 0;
    }

    const set: Set<number> = new Set(nums);
    let result = 1;
    for (const num of set) {
        if (!set.has(num - 1)) {
            let curNum = num;
            let sequence = 1;
            while (set.has(curNum + 1)) {
                sequence++;
                curNum++;
            }

            result = Math.max(result, sequence);
        }
    }

    return result;
};

时空复杂度分析

时间复杂度:代码有两层循环,最外层是 O(n)。但是最坏情况下最后一个数会进入内层循环再遍历一遍数组,也就是 O(n),其他情况都是 O(1),所以总的时间复杂度 O(n + n - 1) 去掉常数为 O(n)

空间复杂度:要缓存数组,所以是 O(n)