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). 代码也变得越来越简洁.