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