Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2]
,
The longest consecutive elements sequence is [1, 2, 3, 4]
. Return its length: 4
.
Your algorithm should run in O(n) complexity.
看到这个题目的第一个感觉是用动态规划的方法去做,因为这样时间复杂度可以是O(n),于是进行动态规划的第一步,列出最优子结构,然后就发现不能使用动态规划啦。
然后我就开始了漫无目的的思考,试了了多方案,都没有通过,最后不得已,就查看了讨论里边的优秀代码,整理了思路,在此总结一下。
先贴一下源码。
public:
int longestConsecutive(vector<int> &num) {
int size=num.size();
map<int,int> result;
int longest=1;
if (size<2) {
return size;
}
for (int i=0;i<size;i++) {
// assumption no duplicate
int cur=num[i];
if (result.find(cur)!=result.end()) {
continue;
}
int before=0;
if (result.find(cur-1)!=result.end()) {
before=result[cur-1];
}
int after=0;
if (result.find(cur+1)!=result.end()) {
after=result[cur+1];
}
//change the valu
int curLength=before+after+1;
if (before!=0) {
result[cur-before]=curLength;
}
if (after!=0) {
result[cur+after]=curLength;
}
result[cur]=curLength;
longest=max(longest,curLength);
}
return longest;
}
};
其实我现在还有部分不太了解的问题,主要是涉及map的插入时间是否对算法的整体运算时间有较大的影响。由于map的细节不太了解,这里也不展开说明啦
说一下大概思路吧,这个算法主要是使用哈希表存储一个位置和其所在的连续相临的长度。从而只使用一个对全部数组的遍历,额外的时间花费就主要集中在对哈希表的读写上。哈希表的键就是对应位置的值,而值就是这个值所在的连续数字列表的长度。这个哈希表为result,每次读取一个位置的值cur,则查看result是否有cur+1,cur-1这两个键值,如果有的话,分别读出其值保存到after,before中,所以cur所在的连续数字列表的长度就是after+before+1,然后result[cur]=after+before+1,然后在改变cur+after,和cur-before在result中的值。
读到这里,大家可能会有一些疑问,为什么只是改变了cur+after和cur-before的值呢?为什么不将连续数组列表中的所有值对应的键值都改变。其实这是由于这道题目的特点和我们处理的方式所决定的,首先,与一个数字连续的数字只有2个,所以result中的作为键的一个数字,理论上只会被访问两次,而且作为连续数字列表中间的值,是不会再被访问到的,只有连续数字两端的值会被访问到。所以,cur+after和cur-before就是连续数字两端的值。