思路一:先对给定数组nums进行排序,然后借助哈希表,使用双指针遍历数组,将数字连续序列以其长度为键插入哈希表中,哈希表中最大的键就是最长数字连续序列的长度
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if (nums.empty()) return 0;
// 排序数组
sort(nums.begin(), nums.end());
// 双指针初始化
int left = 0, right = 0;
int max_len = 1;
while (right < nums.size()) {
if (right > 0 && nums[right] == nums[right - 1] + 1) {
// 当前数字连续,扩展右指针
right++;
} else if (right > 0 && nums[right] == nums[right - 1]) {
// 跳过重复元素
right++;
} else {
// 当前数字不连续,更新最大长度并重置左指针
max_len = max(max_len, right - left);
left = right; // 移动左指针到当前位置
right++;
}
}
// 更新最大长度,防止遗漏最后一个连续序列
max_len = max(max_len, right - left);
return max_len;
}
};
异想天开之错误记录:使用双指针时遇到右指针超出规定界限的问题,导致编译错误,错误代码如下:
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
//先对给定数组nums进行排序,然后借助哈希表,使用双指针遍历数组,
//将数字连续序列以其长度为键插入哈希表中,哈希表中最大的键就是最长数字连续序列的长度
int length = 0;
unordered_map<int, int> hm;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++){
int left = i, right = left;
while(left <= right){
if((nums[left] == nums[right]-1) || nums[left] == nums[right]){
hm[right-left].push_back(nums[right]);
right++;
}
else{
break;
}
}
}
for(auto &it: hm){
int max_key = 1;
if(it->first > max_key){
max_key = it->first;
}
return max_key;
}
return 1;
}
};
但是,哈希表完全可以使用变量来代替,使用哈希表会造成资源浪费,且时间复杂度为O(nlogn),不满足题目要求
思路二:遍历数组nums,找出连续的整数序列,记录其长度,然后将现有数字连续序列长度与最长序列的长度进行比较,得出数字连续的最长序列(不要求序列元素在原数组中连续)的长度
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int current_len = 1,max_len = 1;
if(nums.empty()){
return 0;
}
sort(nums.begin(), nums.end());
for (int i = 1; i < nums.size(); i++) {
if (nums[i] == nums[i - 1]) {
// 跳过重复的数字
continue;
} else if (nums[i] == nums[i - 1] + 1) {
// 如果连续,增加当前长度
current_len++;
} else {
// 不连续,更新最大长度并重置当前长度
max_len = max(max_len, current_len);
current_len = 1;
}
}
max_len = max(max_len, current_len);
return max_len;
}
};
这段代码的时间复杂度仍然为O(nlogn),不满足题目要求
两个思路的时间复杂度主要因为排序!!!
思路三:先借助哈希表对数组进行去重,然后在哈希表中查找表中每个数的前驱数,不存在则说明该数为一段连续序列的起始数字,从该数开始在哈希表中寻找其后继数,存在即更新该数所在连续序列的长度,最终将每段连续序列的长度不断进行比较得到最长长度
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
//先借助哈希表对数组进行去重,在哈希表中查找表中整数的前驱数,
//存在则更新连续数字长度
int max_len = 0;
unordered_set<int> hm;
//利用容器unordered_set的特性去除数组nums中的重复值
for(const int &num:nums){
hm.insert(num);
}
//在哈希表中查找前驱数是否存在
for(const int &num:hm){
if(!hm.count(num - 1)){
int current_num = num;
int current_len = 1;
while(hm.count(current_num +1)){
current_num++;
current_len++;
}
max_len = max(max_len, current_len);
}
}
return max_len;
}
};
注意:
1.it->first及it->second的使用
it->first
的语法适用于存储键值对的容器(如map
或unordered_map
),其中first
表示键,second
表示值- 对于数组或
vector
,迭代器指向单个元素,元素本身没有first
成员,因此使用it->first
会导致编译错误。
2.哈希表类型
unordered_set
:只存储唯一元素。unordered_map
:存储键值对,键唯一。unordered_multiset
:允许重复元素。unordered_multimap
:允许重复键的键值对。
3.count()方法的使用
count()
只判断键或值是否存在(对于set
/unordered_set
),或者统计出现的次数(对于multiset
)。find()
返回迭代器:- 如果找到元素,则返回指向该元素的迭代器。
- 如果未找到元素,则返回
end()
。