目录
1,题目描述
英文描述
中文描述
2,解题思路
第一博(set中元素递增)
第二搏(剪枝,每次都挑选一个完全新的开始元素x【不存在x-1】开始查找)
第三搏(并查集)
3,AC代码
第一博
第二搏
第三搏
4,解题过程
第一博
第二搏
第三搏
1,题目描述
英文描述
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
Your algorithm should run in O(n) complexity.
Example:
Input: [100, 4, 200, 1, 3, 2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
中文描述
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2,解题思路
第一博(set中元素递增)
借助于STL中set的三个优点:无重复元素,元素按照默认递增排列,插入、查找、删除时间复杂度O(logN);
- 先将数据依次插入set<int> record中,去重;
- 接着遍历record中每个元素,若当前元素 *it 比上一元素lastNum大一,说明数据连续,更新连续数字的长度tem++;
- 否则,说明连续中断,更新ans = max(ans, tem);
第二搏(剪枝,每次都挑选一个完全新的开始元素x【不存在x-1】开始查找)
参考@力扣官方题解【最长连续序列】
利用unordered_set去重,遍历去重后的每一个元素x;
若x - 1存在于原数组中,则跳过;
否则查看与x连续的元素最远可到达的位置;
根据最远的位置更新ans;
第三搏(并查集)
不熟悉并查集的同学可以看这里@&再见萤火虫&【并查集【算法笔记/晴神笔记】】
参考@leck【c++并查集写法,代码极短】
unordered_map<int, int> father:key元素,value元素对应父节点(这种数据结构可以调用函数count来查看key是否存在);
father初始化:father[i] = i + 1;(这样便可以依据father[i]来寻找源头);
find函数设计:采用递归+路径压缩的方式;
遍历时,找到每个元素x的根节点y,利用y-x更新ans;
举个例子:
- 初始化map:[100:101,4:5,200:201,1:2,3:4,2:3];
- 当遍历到1时,顺着找1-》2,2-》3,3-》4,4-》5,5-》5,所以ans更新为4;
3,AC代码
第一博
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if(nums.size() == 0) return 0;
set<int> record; // 是set而不是unordered_set
for(int x : nums) record.insert(x);
set<int>::iterator it = record.begin(); // 迭代器it
int ans = 0, lastNum = *it, tem = 1;
while(++it != record.end()){
if(*it == lastNum + 1) tem++;
else{
ans = max(ans, tem);
tem = 1;
}
lastNum = *it;
}
ans = max(ans, tem);
return ans;
}
};
第二搏
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int ans = 0;
unordered_set<int> record;
for(int x : nums) record.insert(x); // 去重
for(int x : record){
if(record.count(x - 1) == 0) {
int curNum = x;
int curAns = 1;
while(record.count(x + 1) != 0) {
curNum = ++x;
curAns++;
}
ans = max(ans, curAns);
}
}
return ans;
}
};
第三搏
class Solution {
public:
unordered_map<int, int> father;
int find(int x) {
if(father.count(x)) {
father[x] = find(father[x]); // 递归进行路径压缩
}else {
return x;
}
return father[x];
}
int longestConsecutive(vector<int>& nums) {
int ans = 0;
for(int x : nums)
father[x] = x + 1; // 每个节点的父亲初始化为x+1
for(int x : nums) {
int y = find(x);
ans = max(ans, y - x);
}
return ans;
}
};
4,解题过程
第一博
set集合内在数据结构为红黑树,插入、查看、删除的时间复杂度均为O(logN),而且存入set集合的元素有个特点,就是顺序按照字典序递增。
所以这一题侥幸过关了:set中插入所有元素,再次遍历,获得结果;
第二搏
查看了官方题解,大致思路是先把所有元素插入到unordered_set中去重;
遍历去重后的数组元素x,若发现x - 1存在于数组中,则跳过;
否则就查看x+1、x+2、......x+i是否存在于数组中,并更新最大长度ans;
第三搏
看到有位大佬使用了并查集来做,感觉思路还挺巧的,于是拿来试一试,但是效率并不是太理想