欢迎访问LeetCode题解合集
题目描述
给定一个未排序的整数数组 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
提示:
- $0 \le nums.length \le 10^4$
- $-10^9 \le nums[i] \le 10^9$
题解:
-
使用一个哈希表
unordered_map<int,int> hash
记录元素所在最长连续序列的长度。 -
从左往右遍历
nums
,假设遍历到nums[i]
,如果nums[i]
之前出现过,则跳过重复元素。对于每个未出现过的nums[i]
元素,有四种情况: nums[i] - 1
和nums[i] + 1
均未出现,则hash[nums[i]] = 1
- 只有
nums[i] - 1
出现,且nums[i] - 1
是最长连续序列的右边界,将nums[i]
接在nums[i] - 1
右边,更新哈希表中新的左右边界对应的长度 - 只有
nums[i] + 1
出现,且nums[i] - 1
是最长连续序列的左边界,将nums[i]
接在nums[i] + 1
左边,更新哈希表中新的左右边界对应的长度 -
nums[i] - 1
和nums[i] + 1
均出现,且它俩分别是各自所在最长连续序列的右边界和左边界,将nums[i]
接在两者中间,然后更新哈希表中新的左右边界对应的长度 -
更新过程中保存最大值即可
时间复杂度:$O(n)$
额外空间复杂度:$O(n)$
class Solution {
public:
unordered_map<int, int> hash;
int merge( int less, int more ) {
int l = less - hash[less] + 1;
int r = more + hash[more] - 1;
int len = r - l + 1;
hash[l] = hash[r] = len;
return len;
}
int longestConsecutive(vector<int>& nums) {
if ( nums.size() < 2 ) return nums.size();
int max_len = 1;
for( const auto& it : nums ) {
if( hash.count( it ) ) continue;
hash[it] = 1;
if ( hash.count( it - 1 ) ) {
max_len = max( max_len, merge( it - 1, it ) );
}
if ( hash.count( it + 1 ) ) {
max_len = max( max_len, merge( it, it + 1 ) );
}
}
return max_len;
}
};
/*
时间:8ms,击败:95.36%
内存:10.3MB,击败:79.15%
*/
当然也可以利用 unordered_map
中未出现的元素初值为 0
,省去判断,但是哈希表中多插入了一些元素:
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if ( nums.size() < 2 ) return nums.size();
unordered_map<int, int> hash;
int max_len = 1;
int l, r, gap;
for( const auto& it : nums ) {
if ( hash[it] ) continue;
hash[it] = 1;
l = hash[it - 1];
r = hash[it + 1];
gap = l + r + 1;
max_len = max( max_len, gap );
hash[it - l] = hash[it + r] = gap;
}
return max_len;
}
};
/*
时间:12ms,击败:83.88%
内存:10.4MB,击败:66.39%
*/