LeetCode128—Longest Consecutive Sequence

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可达。

关于连通分量,不在同一个连通分量的两个节点肯定不可达,在同一个连通分量里面的所有节点都可以通过图的传递性得到其可达的结论。因此:

  1. 先将vector中的数据保存到unordered_set中,因为需要大量的查找,在unordered_set中查找效率是 O(logn)
  2. 选一个节点(可以任意),向左右两个方向搜索,并记录已经访问的节点,因为一个节点不可能出现在两个连通分量中,所以访问一次就够了,并记录连通分量中元素个数。
  3. 直到容器中的节点都被访问过。

代码

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;

    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值