[LeetCode] 128 最长连续系列

197 阅读2分钟

128 最长连续系列

问题描述

给定一个未排序的整数数组,找出最长连续系列的长度。

示例:

输入:[100,4,200,1,3,2]

输出:4

解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。

解题思路:

1、枚举数组中的每一个元素,计算以该元素开头的最大子序列的长度,取所有长度中最长的即可

2、计算以某元素开头子序列长度的方法:以该元素值开始,每次元素值加1,检测加1之后的值在系列中是否存在,存在的话,再枚举下一个值,不存在的话,说明当前长度已经最大。

代码如下:

var longestConsecutive = function(nums) {
    if (!nums && nums.length == 0) {
        return 0;
    }
    let maxLen = 0;
    for (let num of nums) {
        let curNum = num;
        let curLen = 1;
        while (arrContains(nums, curNum + 1)) {
            curNum++;
            curLen++;
        }
        maxLen = Math.max(maxLen, curLen);
    }
    return maxLen;
};

判断元素在系列中存不存在的函数如下:

function arrContains(nums, num) {
    for (let i = 0; i< nums.length; i++) {
        if (nums[i] == num) {
            return true;
        }
    }
    return false;
}

复杂度分析:

以每个元素开头循环n次,计算子序列的while循环的时间复杂度O(n), 对数组的查询O(n),所以整体的时间复杂度O(n^3)

时间复杂度较高,我们可以看看怎么对这种暴力方法进行优化:

判断元素在系列中存不存在的函数,每次都是O(n)的复杂度,可以提前把数据放到set中,这样每次查询就只需要O(1)了。

改造之后的代码:

var longestConsecutive = function(nums) {
        if (!nums && nums.length == 0) {
        return 0;
    }
    let numSet = new Set(nums);
    let maxLen = 1;
    for (let num of numSet) {
        let curNum = num;
        let curLen = 1;
        while (numSet.has(curNum + 1)) {
            curNum++;
            curLen++;
        }
        maxLen = Math.max(maxLen, curLen);
    }
    return maxLen;
};

时间复杂度分析:以每个元素开头循环n次,计算子序列的while循环的时间复杂度O(n), 对数组的查询O(1),所以整体的时间复杂度O(n^2)

这样时间复杂度还是很高,我们可以接着优化:

对于序列中的元素,如果(元素值 - 1)在序列中存在,则以该元素开头的子序列长度,一定小于以元素值 - 1的元素值开头的子序列长度,基于这种情况,该元素开头的子序列长度就没有必要进行判断了。

即元素值-1在序列中存在,则以该元素值开头的子序列长度可以不考虑。

代码如下:

var longestConsecutive = function(nums) {
        if (!nums && nums.length == 0) {
        return 0;
    }
    let numSet = new Set(nums);
    let maxLen = 0;
    for (let num of numSet) {
        if (numSet.has(num - 1)) {
            continue;
        }
        let curNum = num;
        let curLen = 1;
        while (numSet.has(curNum + 1)) {
            curNum++;
            curLen++;
        }
        maxLen = Math.max(maxLen, curLen);
    }
    return maxLen;
};

时间复杂度分析:由于for循环会提前进行判断,所以整体的时间复杂度是O(n+n)=O(n),经过两次优化我们把时间复杂度从O(n^3)降低到了O(n). 代码也变得越来越简洁.