LeetCode128—Longest Consecutive Sequence
原题
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.
在未排序的队列中找到最长连续子串。
分析1
比较朴素的方法,LeetCode对时间的要求不是很高,虽然题目中说了要
O(n)
复杂度,但下述方法能够通过。
1.首先如果不考虑时间这个条件的话,最能想到的就是先排序
O(nlogn)
,当然可以考虑用线性排序算法例如计数排序,不过从容器的数据来看,并不太适合,因为虽然能将复杂度控制到线性范围,但是空间上会可能会出问题。
2. 排完序就简单了,从头到尾扫一遍,对递增序列计数,遇到相同的不计数,遇到不满足条件则把计数清零并记录当前最大值。
这个思路还是比较简单的,但是由于用到了排序和线性扫描,时间复杂度为 O(nlogn)+O(n) ,是不满足题目要求的,虽然可以通过(进一步说明了LeetCode OJ对时间的要求并不是那么严格)
代码1
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
if (nums.size() == 1)
return 1;
sort(nums.begin(), nums.end());//排序
int count = 1;
int maxCount = 1;
for (int i = 0; i < nums.size(); i++)
{
if (nums[i + 1] == nums[i] + 1)//满足要求则count++
count++;
else if (nums[i + 1] == nums[i])//相等不计数
continue;
else//出现不满足条件时记录当前最大并count返回
{
if (maxCount < count)
maxCount = count;
count = 1;
}
}
if (maxCount < count)//这里是必要的,防止不进入最后一个条件判断里面
maxCount = count;
return maxCount;
}
};
分析2
现在就要想如何在线性时间内解决这个问题:
把其划分到一个隐式的图论问题的话,可以理解为求其最大连通分量,容器中的数字表示图中的节点,节点中的值加1或者减1后的新值是否在容器中表示两个节点是否可达:
例如现在vector中是{1,2,3,4,5,8}
我们就说节点1,2可达、2,3可达,利用图的传递性可求其连通分量,即1,2可达、2,3可达,则1,3可达。
关于连通分量,不在同一个连通分量的两个节点肯定不可达,在同一个连通分量里面的所有节点都可以通过图的传递性得到其可达的结论。因此:
- 先将vector中的数据保存到unordered_set中,因为需要大量的查找,在unordered_set中查找效率是 O(logn)
- 选一个节点(可以任意),向左右两个方向搜索,并记录已经访问的节点,因为一个节点不可能出现在两个连通分量中,所以访问一次就够了,并记录连通分量中元素个数。
- 直到容器中的节点都被访问过。
代码
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> numSet(nums.begin(), nums.end());
unordered_set<int> visit;
int count = 1;
int maxCount = 0;
for (auto it = numSet.begin();it!=numSet.end();it++)
{
int curr = *it;
int i = curr + 1;
int count = 1;
while (true)
{
if (numSet.find(i) != numSet.end() && visit.find(i) == visit.end())
{
count++;
visit.insert(i);
i++;
}
else
break;
}
i = curr - 1;
while (true)
{
if (numSet.find(i) != numSet.end() && visit.find(i) == visit.end())
{
count++;
visit.insert(i);
i--;
}
else
break;
}
if (maxCount < count)
maxCount = count;
if (visit.size() == numSet.size())
return maxCount;
}
return maxCount;
}
};